2
0

GR32_Polygons.AggLite.pas 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794
  1. unit GR32_Polygons.AggLite;
  2. (* ***** BEGIN LICENSE BLOCK *****
  3. * Version: MPL 1.1 or LGPL 2.1 with linking exception
  4. *
  5. * The contents of this file are subject to the Mozilla Public License Version
  6. * 1.1 (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. * http://www.mozilla.org/MPL/
  9. *
  10. * Software distributed under the License is distributed on an "AS IS" basis,
  11. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12. * for the specific language governing rights and limitations under the
  13. * License.
  14. *
  15. * Alternatively, the contents of this file may be used under the terms of the
  16. * Free Pascal modified version of the GNU Lesser General Public License
  17. * Version 2.1 (the "FPC modified LGPL License"), in which case the provisions
  18. * of this license are applicable instead of those above.
  19. * Please see the file LICENSE.txt for additional information concerning this
  20. * license.
  21. *
  22. * The Original Code is a mixture of AggLite and the other polygon renderers of
  23. * Graphics32
  24. *
  25. * The Initial Developer is
  26. * Christian-W. Budde <[email protected]>
  27. *
  28. * Portions created by the Initial Developer are Copyright (C) 2008-2012
  29. * the Initial Developer. All Rights Reserved.
  30. *
  31. * AggLite is based on Anti-Grain Geometry (Version 2.0)
  32. * Copyright (C) 2002-2004 Maxim Shemanarev (McSeem)
  33. *
  34. * Permission to copy, use, modify, sell and distribute this software
  35. * is granted provided this copyright notice appears in all copies.
  36. * This software is provided "as is" without express or implied
  37. * warranty, and with no claim as to its suitability for any purpose.
  38. *
  39. * Contributor(s):
  40. *
  41. * ***** END LICENSE BLOCK ***** *)
  42. interface
  43. {$include GR32.inc}
  44. {$IFDEF FPC}
  45. {$DEFINE PUREPASCAL}
  46. {$ENDIF}
  47. uses
  48. Types, GR32, GR32_Polygons, GR32_Transforms;
  49. type
  50. TPolygonRenderer32AggLite = class(TPolygonRenderer32)
  51. protected
  52. procedure Render(CellsPtr: Pointer; MinX, MaxX: Integer);
  53. public
  54. procedure PolygonFS(const Points: TArrayOfFloatPoint;
  55. const ClipRect: TFloatRect); override;
  56. procedure PolyPolygonFS(const Points: TArrayOfArrayOfFloatPoint;
  57. const ClipRect: TFloatRect); override;
  58. end;
  59. procedure PolyPolygonFS_AggLite(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFloatPoint;
  60. Color: TColor32; FillMode: TPolyFillMode = pfAlternate;
  61. Transformation: TTransformation = nil); overload;
  62. procedure PolygonFS_AggLite(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint;
  63. Color: TColor32; FillMode: TPolyFillMode = pfAlternate;
  64. Transformation: TTransformation = nil); overload;
  65. procedure PolyPolygonFS_AggLite(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFloatPoint;
  66. Filler: TCustomPolygonFiller; FillMode: TPolyFillMode = pfAlternate;
  67. Transformation: TTransformation = nil); overload;
  68. procedure PolygonFS_AggLite(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint;
  69. Filler: TCustomPolygonFiller; FillMode: TPolyFillMode = pfAlternate;
  70. Transformation: TTransformation = nil); overload;
  71. procedure PolyPolygonFS_AggLite(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFloatPoint;
  72. ClipRect: TRect; Color: TColor32; FillMode: TPolyFillMode = pfAlternate;
  73. Transformation: TTransformation = nil); overload;
  74. procedure PolygonFS_AggLite(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint;
  75. ClipRect: TRect; Color: TColor32; FillMode: TPolyFillMode = pfAlternate;
  76. Transformation: TTransformation = nil); overload;
  77. procedure PolyPolygonFS_AggLite(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFloatPoint;
  78. ClipRect: TRect; Filler: TCustomPolygonFiller; FillMode: TPolyFillMode = pfAlternate;
  79. Transformation: TTransformation = nil); overload;
  80. procedure PolygonFS_AggLite(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint;
  81. ClipRect: TRect; Filler: TCustomPolygonFiller; FillMode: TPolyFillMode = pfAlternate;
  82. Transformation: TTransformation = nil); overload;
  83. procedure PolyPolylineFS_AggLite(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFloatPoint;
  84. Color: TColor32; Closed: Boolean = False; StrokeWidth: TFloat = 1.0;
  85. JoinStyle: TJoinStyle = jsMiter; EndStyle: TEndStyle = esButt;
  86. MiterLimit: TFloat = 4.0; Transformation: TTransformation = nil); overload;
  87. procedure PolyPolylineFS_AggLite(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFloatPoint;
  88. Filler: TCustomPolygonFiller; Closed: Boolean = False; StrokeWidth: TFloat = 1.0;
  89. JoinStyle: TJoinStyle = jsMiter; EndStyle: TEndStyle = esButt;
  90. MiterLimit: TFloat = 4.0; Transformation: TTransformation = nil); overload;
  91. procedure PolylineFS_AggLite(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint;
  92. Color: TColor32; Closed: Boolean = False; StrokeWidth: TFloat = 1.0;
  93. JoinStyle: TJoinStyle = jsMiter; EndStyle: TEndStyle = esButt;
  94. MiterLimit: TFloat = 4.0; Transformation: TTransformation = nil); overload;
  95. procedure PolylineFS_AggLite(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint;
  96. Filler: TCustomPolygonFiller; Closed: Boolean = False; StrokeWidth: TFloat = 1.0;
  97. JoinStyle: TJoinStyle = jsMiter; EndStyle: TEndStyle = esButt;
  98. MiterLimit: TFloat = 4.0; Transformation: TTransformation = nil); overload;
  99. procedure DashLineFS_AggLite(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint;
  100. const Dashes: TArrayOfFloat; Color: TColor32;
  101. Closed: Boolean = False; Width: TFloat = 1.0); overload;
  102. procedure DashLineFS_AggLite(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint;
  103. const Dashes: TArrayOfFloat; FillColor, StrokeColor: TColor32;
  104. Closed: Boolean; Width: TFloat; StrokeWidth: TFloat = 2.0); overload;
  105. procedure DashLineFS_AggLite(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint;
  106. const Dashes: TArrayOfFloat; Filler: TCustomPolygonFiller;
  107. Closed: Boolean = False; Width: TFloat = 1.0); overload;
  108. procedure DashLineFS_AggLite(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint;
  109. const Dashes: TArrayOfFloat; Filler: TCustomPolygonFiller; StrokeColor: TColor32;
  110. Closed: Boolean; Width: TFloat; StrokeWidth: TFloat = 2.0); overload;
  111. implementation
  112. uses
  113. Math,
  114. GR32_Blend,
  115. GR32_Gamma,
  116. GR32_LowLevel,
  117. GR32_Bindings,
  118. GR32_VectorUtils;
  119. procedure PolyPolygonFS_AggLite(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFloatPoint;
  120. Color: TColor32; FillMode: TPolyFillMode; Transformation: TTransformation);
  121. var
  122. Renderer: TPolygonRenderer32AggLite;
  123. begin
  124. Renderer := TPolygonRenderer32AggLite.Create;
  125. try
  126. Renderer.Bitmap := Bitmap;
  127. Renderer.Color := Color;
  128. Renderer.FillMode := FillMode;
  129. Renderer.PolyPolygonFS(Points, FloatRect(Bitmap.ClipRect), Transformation);
  130. finally
  131. Renderer.Free;
  132. end;
  133. end;
  134. procedure PolygonFS_AggLite(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint;
  135. Color: TColor32; FillMode: TPolyFillMode; Transformation: TTransformation);
  136. var
  137. Renderer: TPolygonRenderer32AggLite;
  138. begin
  139. Renderer := TPolygonRenderer32AggLite.Create;
  140. try
  141. Renderer.Bitmap := Bitmap;
  142. Renderer.Color := Color;
  143. Renderer.FillMode := FillMode;
  144. Renderer.PolygonFS(Points, FloatRect(Bitmap.ClipRect), Transformation);
  145. finally
  146. Renderer.Free;
  147. end;
  148. end;
  149. procedure PolyPolygonFS_AggLite(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFloatPoint;
  150. Filler: TCustomPolygonFiller; FillMode: TPolyFillMode; Transformation: TTransformation);
  151. var
  152. Renderer: TPolygonRenderer32AggLite;
  153. begin
  154. if not Assigned(Filler) then Exit;
  155. Renderer := TPolygonRenderer32AggLite.Create;
  156. try
  157. Renderer.Bitmap := Bitmap;
  158. Renderer.Filler := Filler;
  159. Renderer.FillMode := FillMode;
  160. Renderer.PolyPolygonFS(Points, FloatRect(Bitmap.ClipRect), Transformation);
  161. finally
  162. Renderer.Free;
  163. end;
  164. end;
  165. procedure PolygonFS_AggLite(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint;
  166. Filler: TCustomPolygonFiller; FillMode: TPolyFillMode; Transformation: TTransformation);
  167. var
  168. Renderer: TPolygonRenderer32AggLite;
  169. begin
  170. if not Assigned(Filler) then Exit;
  171. Renderer := TPolygonRenderer32AggLite.Create;
  172. try
  173. Renderer.Bitmap := Bitmap;
  174. Renderer.Filler := Filler;
  175. Renderer.FillMode := FillMode;
  176. Renderer.PolygonFS(Points, FloatRect(Bitmap.ClipRect), Transformation);
  177. finally
  178. Renderer.Free;
  179. end;
  180. end;
  181. procedure PolyPolygonFS_AggLite(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFloatPoint;
  182. ClipRect: TRect; Color: TColor32; FillMode: TPolyFillMode;
  183. Transformation: TTransformation);
  184. var
  185. Renderer: TPolygonRenderer32AggLite;
  186. IntersectedClipRect: TRect;
  187. begin
  188. Renderer := TPolygonRenderer32AggLite.Create;
  189. try
  190. Renderer.Bitmap := Bitmap;
  191. Renderer.Color := Color;
  192. Renderer.FillMode := FillMode;
  193. GR32.IntersectRect(IntersectedClipRect, Bitmap.ClipRect, ClipRect);
  194. Renderer.PolyPolygonFS(Points, FloatRect(IntersectedClipRect), Transformation);
  195. finally
  196. Renderer.Free;
  197. end;
  198. end;
  199. procedure PolygonFS_AggLite(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint;
  200. ClipRect: TRect; Color: TColor32; FillMode: TPolyFillMode;
  201. Transformation: TTransformation);
  202. var
  203. Renderer: TPolygonRenderer32AggLite;
  204. IntersectedClipRect: TRect;
  205. begin
  206. Renderer := TPolygonRenderer32AggLite.Create;
  207. try
  208. Renderer.Bitmap := Bitmap;
  209. Renderer.Color := Color;
  210. Renderer.FillMode := FillMode;
  211. GR32.IntersectRect(IntersectedClipRect, Bitmap.ClipRect, ClipRect);
  212. Renderer.PolygonFS(Points, FloatRect(IntersectedClipRect), Transformation);
  213. finally
  214. Renderer.Free;
  215. end;
  216. end;
  217. procedure PolyPolygonFS_AggLite(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFloatPoint;
  218. ClipRect: TRect; Filler: TCustomPolygonFiller; FillMode: TPolyFillMode;
  219. Transformation: TTransformation);
  220. var
  221. Renderer: TPolygonRenderer32AggLite;
  222. IntersectedClipRect: TRect;
  223. begin
  224. if not Assigned(Filler) then Exit;
  225. Renderer := TPolygonRenderer32AggLite.Create;
  226. try
  227. Renderer.Bitmap := Bitmap;
  228. Renderer.Filler := Filler;
  229. Renderer.FillMode := FillMode;
  230. GR32.IntersectRect(IntersectedClipRect, Bitmap.ClipRect, ClipRect);
  231. Renderer.PolyPolygonFS(Points, FloatRect(IntersectedClipRect), Transformation);
  232. finally
  233. Renderer.Free;
  234. end;
  235. end;
  236. procedure PolygonFS_AggLite(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint;
  237. ClipRect: TRect; Filler: TCustomPolygonFiller; FillMode: TPolyFillMode;
  238. Transformation: TTransformation);
  239. var
  240. Renderer: TPolygonRenderer32AggLite;
  241. IntersectedClipRect: TRect;
  242. begin
  243. if not Assigned(Filler) then Exit;
  244. Renderer := TPolygonRenderer32AggLite.Create;
  245. try
  246. Renderer.Bitmap := Bitmap;
  247. Renderer.Filler := Filler;
  248. Renderer.FillMode := FillMode;
  249. GR32.IntersectRect(IntersectedClipRect, Bitmap.ClipRect, ClipRect);
  250. Renderer.PolygonFS(Points, FloatRect(IntersectedClipRect), Transformation);
  251. finally
  252. Renderer.Free;
  253. end;
  254. end;
  255. procedure PolyPolylineFS_AggLite(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFloatPoint;
  256. Color: TColor32; Closed: Boolean; StrokeWidth: TFloat;
  257. JoinStyle: TJoinStyle; EndStyle: TEndStyle;
  258. MiterLimit: TFloat; Transformation: TTransformation);
  259. var
  260. Dst: TArrayOfArrayOfFloatPoint;
  261. begin
  262. Dst := BuildPolyPolyLine(Points, Closed, StrokeWidth, JoinStyle, EndStyle, MiterLimit);
  263. PolyPolygonFS_AggLite(Bitmap, Dst, Color, pfWinding, Transformation);
  264. end;
  265. procedure PolyPolylineFS_AggLite(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFloatPoint;
  266. Filler: TCustomPolygonFiller; Closed: Boolean = False; StrokeWidth: TFloat = 1.0;
  267. JoinStyle: TJoinStyle = jsMiter; EndStyle: TEndStyle = esButt;
  268. MiterLimit: TFloat = 4.0; Transformation: TTransformation = nil);
  269. var
  270. Dst: TArrayOfArrayOfFloatPoint;
  271. begin
  272. Dst := BuildPolyPolyLine(Points, Closed, StrokeWidth, JoinStyle, EndStyle, MiterLimit);
  273. PolyPolygonFS(Bitmap, Dst, Filler, pfWinding, Transformation);
  274. end;
  275. procedure PolylineFS_AggLite(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint;
  276. Color: TColor32; Closed: Boolean; StrokeWidth: TFloat;
  277. JoinStyle: TJoinStyle; EndStyle: TEndStyle;
  278. MiterLimit: TFloat; Transformation: TTransformation);
  279. begin
  280. PolyPolylineFS_AggLite(Bitmap, PolyPolygon(Points), Color, Closed, StrokeWidth,
  281. JoinStyle, EndStyle, MiterLimit, Transformation);
  282. end;
  283. procedure PolylineFS_AggLite(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint;
  284. Filler: TCustomPolygonFiller; Closed: Boolean = False; StrokeWidth: TFloat = 1.0;
  285. JoinStyle: TJoinStyle = jsMiter; EndStyle: TEndStyle = esButt;
  286. MiterLimit: TFloat = 4.0; Transformation: TTransformation = nil);
  287. begin
  288. PolyPolylineFS_AggLite(Bitmap, PolyPolygon(Points), Filler, Closed, StrokeWidth,
  289. JoinStyle, EndStyle, MiterLimit, Transformation);
  290. end;
  291. procedure DashLineFS_AggLite(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint;
  292. const Dashes: TArrayOfFloat; Color: TColor32;
  293. Closed: Boolean = False; Width: TFloat = 1.0);
  294. var
  295. MultiPoly: TArrayOfArrayOfFloatPoint;
  296. begin
  297. MultiPoly := GR32_VectorUtils.BuildDashedLine(Points, Dashes, 0, Closed);
  298. PolyPolylineFS_AggLite(Bitmap, MultiPoly, Color, False, Width);
  299. end;
  300. procedure DashLineFS_AggLite(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint;
  301. const Dashes: TArrayOfFloat; FillColor, StrokeColor: TColor32;
  302. Closed: Boolean; Width: TFloat; StrokeWidth: TFloat = 2.0);
  303. var
  304. MultiPoly: TArrayOfArrayOfFloatPoint;
  305. begin
  306. MultiPoly := GR32_VectorUtils.BuildDashedLine(Points, Dashes, 0, Closed);
  307. MultiPoly := BuildPolyPolyLine(MultiPoly, False, Width);
  308. PolyPolygonFS_AggLite(Bitmap, MultiPoly, FillColor);
  309. PolyPolylineFS_AggLite(Bitmap, MultiPoly, StrokeColor, True, StrokeWidth);
  310. end;
  311. procedure DashLineFS_AggLite(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint;
  312. const Dashes: TArrayOfFloat; Filler: TCustomPolygonFiller;
  313. Closed: Boolean = False; Width: TFloat = 1.0);
  314. var
  315. MultiPoly: TArrayOfArrayOfFloatPoint;
  316. begin
  317. MultiPoly := GR32_VectorUtils.BuildDashedLine(Points, Dashes, 0, Closed);
  318. PolyPolylineFS_AggLite(Bitmap, MultiPoly, Filler, False, Width);
  319. end;
  320. procedure DashLineFS_AggLite(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint;
  321. const Dashes: TArrayOfFloat; Filler: TCustomPolygonFiller; StrokeColor: TColor32;
  322. Closed: Boolean; Width: TFloat; StrokeWidth: TFloat = 2.0);
  323. var
  324. MultiPoly: TArrayOfArrayOfFloatPoint;
  325. begin
  326. MultiPoly := GR32_VectorUtils.BuildDashedLine(Points, Dashes, 0, Closed);
  327. MultiPoly := BuildPolyPolyLine(MultiPoly, False, Width);
  328. PolyPolygonFS_AggLite(Bitmap, MultiPoly, Filler);
  329. PolyPolylineFS_AggLite(Bitmap, MultiPoly, StrokeColor, True, StrokeWidth);
  330. end;
  331. const
  332. CPolyBaseShift = 8;
  333. CPolyBaseSize = 1 shl CPolyBaseShift;
  334. CPolyBaseMask = CPolyBaseSize - 1;
  335. CCellBlockShift = 12;
  336. CCellBlockSize = 1 shl CCellBlockShift;
  337. CCellBlockMask = CCellBlockSize - 1;
  338. CCellBlockPool = 256;
  339. CCellBlockLimit = 1024;
  340. type
  341. PPColor32 = ^PColor32;
  342. TPointWord = record
  343. case Byte of
  344. 0: (X, Y: SmallInt);
  345. 1: (PackedCoord: Integer);
  346. end;
  347. TCell = packed record
  348. Pnt: TPointWord;
  349. PackedCoord: Integer;
  350. Cover: Integer;
  351. Area: Integer;
  352. end;
  353. PCell = ^TCell;
  354. PPCell = ^PCell;
  355. TScanLine = class(TObject)
  356. private
  357. FCounts: PWord;
  358. FCovers: PColor32Array;
  359. FCurCount: PWord;
  360. FCurStartPtr: PPColor32;
  361. FLastX: Integer;
  362. FLastY: Integer;
  363. FMaxLen: Cardinal;
  364. FMinX: Integer;
  365. FNumSpans: Cardinal;
  366. FStartPtrs: PPColor32;
  367. public
  368. constructor Create(MinX, MaxX: Integer);
  369. destructor Destroy; override;
  370. procedure AddCell(X, Y: Integer; Cover: Cardinal);
  371. procedure AddSpan(X, Y: Integer; Len, Cover: Cardinal);
  372. function IsReady(Y: Integer): Integer;
  373. procedure ResetSpans;
  374. property BaseX: Integer read FMinX;
  375. property Y: Integer read FLastY;
  376. property NumSpans: Cardinal read FNumSpans;
  377. property CountsPtr: PWord read FCounts;
  378. property CoversPtr: PColor32Array read FCovers;
  379. property StartPtrs: PPColor32 read FStartPtrs;
  380. end;
  381. TOutlineFlag = (ofNotClosed, ofSortRequired);
  382. TOutlineFlags = set of TOutlineFlag;
  383. TOutline = class(TObject)
  384. private
  385. FCells: PPCell;
  386. FClose: TPoint;
  387. FCurBlock: Cardinal;
  388. FCurCell: TCell;
  389. FCurCellPtr: PCell;
  390. FCur: TPoint;
  391. FFlags: TOutlineFlags;
  392. FMaxBlocks: Cardinal;
  393. FMax: TPoint;
  394. FMin: TPoint;
  395. FNumBlocks: Cardinal;
  396. FNumCells: Cardinal;
  397. FSortedCells: PPCell;
  398. FSortedSize: Cardinal;
  399. procedure AddCurCell;
  400. procedure AllocateBlock;
  401. function GetCells: PPCell;
  402. procedure RenderLine(X1, Y1, X2, Y2: Integer);
  403. procedure RenderScanLine(EY, X1, Y1, X2, Y2: Integer);
  404. procedure SetCurCell(X, Y: Integer);
  405. procedure SortCells;
  406. procedure InternalReset;
  407. public
  408. constructor Create;
  409. destructor Destroy; override;
  410. procedure LineTo(X, Y: Integer);
  411. procedure MoveTo(X, Y: Integer);
  412. procedure Reset;
  413. property Cells: PPCell read GetCells;
  414. property MaxX: Integer read FMax.X;
  415. property MaxY: Integer read FMax.Y;
  416. property MinX: Integer read FMin.X;
  417. property MinY: Integer read FMin.Y;
  418. property NumCells: Cardinal read FNumCells;
  419. end;
  420. function Fixed8(C: TFloat): Integer; {$IFDEF USEINLINING} inline; {$ENDIF}
  421. begin
  422. Result := Trunc(C * CPolyBaseSize);
  423. end;
  424. { TCell }
  425. procedure SetCell(var Cell: TCell; CX, CY: Integer); {$IFDEF USEINLINING} inline; {$ENDIF}
  426. begin
  427. with Cell do
  428. begin
  429. Pnt.X := SmallInt(CX);
  430. Pnt.Y := SmallInt(CY);
  431. PackedCoord := (CY shl 16) + CX;
  432. Cover := 0;
  433. Area := 0;
  434. end;
  435. end;
  436. procedure PartSort(var A, B: PPCell; const Stop: PCell);
  437. {$IFDEF PUREPASCAL}
  438. {$IFDEF USEINLINING} inline; {$ENDIF}
  439. procedure SwapCells(A, B: PPCell); {$IFDEF USEINLINING} inline; {$ENDIF}
  440. var
  441. Temp: PCell;
  442. begin
  443. Temp := A^;
  444. A^ := B^;
  445. B^ := Temp;
  446. end;
  447. begin
  448. while True do
  449. begin
  450. repeat
  451. Inc(A)
  452. until (A^^.PackedCoord >= Stop^.PackedCoord);
  453. repeat
  454. Dec(B)
  455. until (B^^.PackedCoord <= Stop^.PackedCoord);
  456. if NativeUInt(A) > NativeUInt(B) then
  457. Break;
  458. SwapCells(A, B);
  459. end;
  460. {$ELSE}
  461. asm
  462. {$IFDEF CPUX86}
  463. PUSH EBX
  464. PUSH EDI
  465. PUSH ESI
  466. PUSH EBP
  467. MOV ECX, [ECX + 4]
  468. @0:
  469. MOV EDI, [EAX]
  470. @1:
  471. ADD EDI, $04
  472. MOV EBX, [EDI]
  473. CMP ECX, [EBX + 4]
  474. JG @1
  475. MOV [EAX], EDI
  476. MOV EDI, [EDX]
  477. @2:
  478. SUB EDI, $04
  479. MOV EBX, [EDI]
  480. CMP ECX, [EBX + 4]
  481. JL @2
  482. MOV [EDX], EDI
  483. CMP EDI, [EAX]
  484. JLE @3
  485. MOV EBX, [EAX]
  486. MOV ESI, [EBX]
  487. MOV EBP, [EDI]
  488. MOV [EDI], ESI
  489. MOV [EBX], EBP
  490. JMP @0
  491. @3:
  492. POP EBP
  493. POP ESI
  494. POP EDI
  495. POP EBX
  496. {$ENDIF}
  497. {$IFDEF CPUX64}
  498. MOV R8D, [R8 + 4]
  499. @0:
  500. MOV R9, [RCX]
  501. @1:
  502. ADD R9, $08
  503. MOV RAX, [R9]
  504. CMP R8D, [RAX + 4]
  505. JG @1
  506. MOV [RCX], R9
  507. MOV R9, [RDX]
  508. @2:
  509. SUB R9, $08
  510. MOV RAX, [R9]
  511. CMP R8D, [RAX + 4]
  512. JL @2
  513. MOV [RDX], R9
  514. CMP R9, [RCX]
  515. JLE @3
  516. MOV RAX, [RCX]
  517. MOV R10, [RAX]
  518. MOV R11, [R9]
  519. MOV [RAX], R11
  520. MOV [R9], R10
  521. JMP @0
  522. @3:
  523. {$ENDIF}
  524. {$ENDIF}
  525. end;
  526. procedure QSortCells(Start: PPCell; Num: Cardinal);
  527. const
  528. QSortThreshold = 9;
  529. var
  530. Stack: array [0 .. 79] of PPCell;
  531. Top: ^PPCell;
  532. Limit, Base, I, J, Pivot: PPCell;
  533. Len: Integer;
  534. procedure CheckCells(var A, B: PCell); {$IFDEF USEINLINING} inline; {$ENDIF}
  535. var
  536. Temp: PCell;
  537. begin
  538. if A^.PackedCoord < B^.PackedCoord then
  539. begin
  540. Temp := A;
  541. A := B;
  542. B := Temp;
  543. end;
  544. end;
  545. procedure SwapCells(A, B: PPCell); {$IFDEF USEINLINING} inline; {$ENDIF}
  546. var
  547. Temp: PCell;
  548. begin
  549. Temp := A^;
  550. A^ := B^;
  551. B^ := Temp;
  552. end;
  553. function LessThan(A, B: PPCell): Boolean; {$IFDEF USEINLINING} inline; {$ENDIF}
  554. begin
  555. Result := A^^.PackedCoord < B^^.PackedCoord;
  556. end;
  557. begin
  558. Limit := PPCell(NativeUInt(Start) + Num * SizeOf(PCell));
  559. Base := Start;
  560. Top := @Stack[0];
  561. while True do
  562. begin
  563. Len := (NativeInt(Limit) - NativeInt(Base)) div SizeOf(PCell);
  564. if Len > QSortThreshold then
  565. begin
  566. // we use Base + (Len div 2) as the pivot
  567. Pivot := Base;
  568. Inc(Pivot, Len div 2);
  569. SwapCells(Base, Pivot);
  570. I := Base;
  571. Inc(I);
  572. J := Limit;
  573. Dec(J);
  574. // now ensure that I^ <= Base^ <= J^
  575. CheckCells(J^, I^);
  576. CheckCells(Base^, I^);
  577. CheckCells(J^, Base^);
  578. PartSort(I, J, Base^);
  579. SwapCells(Base, J);
  580. // now, push the largest sub-array
  581. if NativeInt(J) - NativeInt(Base) > NativeInt(Limit) - NativeInt(I) then
  582. begin
  583. Top^ := Base;
  584. Inc(Top);
  585. Top^ := J;
  586. Base := I;
  587. end
  588. else
  589. begin
  590. Top^ := I;
  591. Inc(Top);
  592. Top^ := Limit;
  593. Limit := J;
  594. end;
  595. Inc(Top);
  596. end
  597. else
  598. begin
  599. // the sub-array is small, perform insertion sort
  600. J := Base;
  601. I := J;
  602. Inc(I);
  603. while NativeInt(I) < NativeInt(Limit) do
  604. begin
  605. while LessThan(PPCell(NativeUInt(J) + SizeOf(PCell)), J) do
  606. begin
  607. SwapCells(PPCell(NativeUInt(J) + SizeOf(PCell)), J);
  608. if J = Base then
  609. Break;
  610. Dec(J);
  611. end;
  612. J := I;
  613. Inc(I);
  614. end;
  615. if NativeInt(Top) > NativeInt(@Stack[0]) then
  616. begin
  617. Dec(Top, 2);
  618. Base := Top^;
  619. Limit := PPCell(Pointer(NativeInt(Top) + SizeOf(PPCell))^);
  620. end
  621. else
  622. Break;
  623. end;
  624. end;
  625. end;
  626. var
  627. FillSpan: procedure (Ptr: PColor32Array; Covers: PColor32; Count: Cardinal;
  628. const C: TColor32);
  629. procedure FillSpan_Pas(Ptr: PColor32Array; Covers: PColor32; Count: Cardinal;
  630. const C: TColor32);
  631. begin
  632. repeat
  633. BlendMemEx(C, PColor32(Ptr)^, Covers^);
  634. Inc(Covers);
  635. Inc(Ptr);
  636. Dec(Count);
  637. until Count = 0;
  638. end;
  639. {$IFNDEF PUREPASCAL}
  640. procedure FillSpan_ASM(Ptr: PColor32Array; Covers: PColor32; Count: Cardinal;
  641. const C: TColor32);
  642. asm
  643. {$IFDEF CPUX86}
  644. PUSH EBX
  645. PUSH ESI
  646. PUSH EDI
  647. LEA ESI, EDX + 4 * ECX // ESI = Covers
  648. LEA EDI, EAX + 4 * ECX // EDI = P
  649. NEG ECX
  650. @LoopStart:
  651. MOVZX EBX, [ESI + 4 * ECX]
  652. MOVZX EAX, [EBP + $0B] // EAX = C.A
  653. IMUL EBX, EAX // EBX = Alpha
  654. MOVZX EAX, [EDI + 4 * ECX]
  655. MOVZX EDX, [EBP + $08] // EDX = C.R
  656. SUB EDX, EAX
  657. IMUL EDX, EBX
  658. SHL EAX, $10
  659. ADD EDX, EAX
  660. SHR EDX, $10
  661. MOV [EDI + 4 * ECX], DL // store to pointer
  662. MOVZX EAX, [EDI + 4 * ECX + 1]
  663. MOVZX EDX, [EBP + $09] // EDX = C.G
  664. SUB EDX, EAX
  665. IMUL EDX, EBX
  666. SHL EAX, $10
  667. ADD EDX, EAX
  668. SHR EDX, $10
  669. MOV [EDI + 4 * ECX + 1], DL // store to pointer
  670. MOVZX EAX, [EDI + 4 * ECX + 2]
  671. MOVZX EDX, [EBP + $0A] // EDX = C.B
  672. SUB EDX, EAX
  673. IMUL EDX, EBX
  674. SHL EAX, $10
  675. ADD EDX, EAX
  676. SHR EDX, $10
  677. MOV [EDI + 4 * ECX + 2], DL // store to pointer
  678. MOVZX EAX, [EDI + 4 * ECX + 3]
  679. MOVZX EDX, [EBP + $0B] // EDX = C.A
  680. SUB EDX, EAX
  681. IMUL EDX, EBX
  682. SHL EAX, $10
  683. ADD EDX, EAX
  684. SHR EDX, $10
  685. MOV [EDI + 4 * ECX + 3], DL // store to pointer
  686. ADD ECX, 1
  687. JS @LoopStart
  688. POP EDI
  689. POP ESI
  690. POP EBX
  691. {$ENDIF}
  692. {$IFDEF CPUX64}
  693. LEA R10, [RDX + 4 * R8] // R10 = Covers
  694. LEA R11, [RCX + 4 * R8] // R11 = P
  695. NEG R8D
  696. @LoopStart:
  697. MOVZX R9D, [R10 + 4 * R8]
  698. MOVZX ECX, [EBP + $0B] // ECX = C.A
  699. IMUL R9D, ECX // R9D = Alpha
  700. MOVZX ECX, [R11 + 4 * R8]
  701. MOVZX EDX, [EBP + $08] // EDX = C.R
  702. SUB EDX, ECX
  703. IMUL EDX, R9D
  704. SHL ECX, $10
  705. ADD EDX, ECX
  706. SHR EDX, $10
  707. MOV [R11 + 4 * R8], DL // store to pointer
  708. MOVZX ECX, [R11 + 4 * R8 + 1]
  709. MOVZX EDX, [EBP + $09] // EDX = C.G
  710. SUB EDX, ECX
  711. IMUL EDX, R9D
  712. SHL ECX, $10
  713. ADD EDX, ECX
  714. SHR EDX, $10
  715. MOV [R11 + 4 * R8 + 1], DL // store to pointer
  716. MOVZX ECX, [R11 + 4 * R8 + 2]
  717. MOVZX EDX, [EBP + $0A] // EDX = C.B
  718. SUB EDX, ECX
  719. IMUL EDX, R9D
  720. SHL ECX, $10
  721. ADD EDX, ECX
  722. SHR EDX, $10
  723. MOV [R11 + 4 * R8 + 2], DL // store to pointer
  724. MOVZX ECX, [R11 + 4 * R8 + 3]
  725. MOVZX EDX, [EBP + $0B] // EDX = C.A
  726. SUB EDX, ECX
  727. IMUL EDX, R9D
  728. SHL ECX, $10
  729. ADD EDX, ECX
  730. SHR EDX, $10
  731. MOV [R11 + 4 * R8 + 3], DL // store to pointer
  732. ADD R8D, 1
  733. JS @LoopStart
  734. {$ENDIF}
  735. end;
  736. {$IFNDEF OMIT_SSE2}
  737. procedure FillSpan_SSE2(Ptr: PColor32Array; Covers: PColor32; Count: Cardinal;
  738. const C: TColor32);
  739. asm
  740. {$IFDEF TARGET_X86}
  741. JCXZ @5
  742. PUSH EBX
  743. MOV EBX,C
  744. PXOR XMM7,XMM7 // XMM7 = 0
  745. MOVD XMM1,EBX // XMM1 = C (Foreground)
  746. PUNPCKLBW XMM1,XMM7
  747. SHR EBX,24
  748. JZ @4
  749. INC EBX // 255:256 range bias
  750. PUSH ESI
  751. MOV ESI,EAX
  752. @1: MOVQ XMM0,XMM1
  753. MOVD XMM2,[ESI] // XMM2 = Dest (Background)
  754. PUNPCKLBW XMM2,XMM7
  755. MOV EAX,[EDX] // EAX = Alpha
  756. IMUL EAX,EBX
  757. SHR EAX,8
  758. JZ @3
  759. CMP EAX,$FF
  760. JZ @2
  761. SHL EAX,4
  762. ADD EAX,alpha_ptr
  763. PSUBW XMM0,XMM2
  764. PMULLW XMM0,[EAX]
  765. PSLLW XMM2,8
  766. MOV EAX,bias_ptr
  767. PADDW XMM2,[EAX]
  768. PADDW XMM0,XMM2
  769. PSRLW XMM0,8
  770. @2: PACKUSWB XMM0,XMM7
  771. MOVD [ESI],XMM0
  772. @3: ADD ESI,4
  773. ADD EDX,4
  774. DEC ECX
  775. JNZ @1
  776. POP ESI
  777. @4: POP EBX
  778. @5:
  779. {$ENDIF}
  780. {$IFDEF TARGET_X64}
  781. TEST R8D,R8D
  782. JZ @4
  783. PXOR XMM7,XMM7 // XMM7 = 0
  784. MOVD XMM1,R9D // XMM1 = C (Foreground)
  785. PUNPCKLBW XMM1,XMM7
  786. SHR R9D,24
  787. JZ @2
  788. INC R9D // 255:256 range bias
  789. @1: MOVQ XMM0,XMM1
  790. MOVD XMM2,[RCX] // XMM2 = Dest (Background)
  791. PUNPCKLBW XMM2,XMM7
  792. MOV EAX,[RDX] // EAX = Alpha
  793. IMUL EAX,R9D
  794. SHR EAX,8
  795. JZ @3
  796. CMP EAX,$FF
  797. JZ @2
  798. SHL EAX,4
  799. ADD RAX,alpha_ptr
  800. PSUBW XMM0,XMM2
  801. PMULLW XMM0,[RAX]
  802. PSLLW XMM2,8
  803. MOV RAX,bias_ptr
  804. PADDW XMM2,[RAX]
  805. PADDW XMM0,XMM2
  806. PSRLW XMM0,8
  807. @2: PACKUSWB XMM0,XMM7
  808. MOVD [RCX],XMM0
  809. @3: ADD ECX,4
  810. ADD EDX,4
  811. DEC R8D
  812. JNZ @1
  813. @4:
  814. {$ENDIF}
  815. end;
  816. {$ENDIF}
  817. {$ENDIF}
  818. function CalculateAlpha(FillMode: TPolyFillMode; Area: Integer): Cardinal;
  819. var
  820. Cover: Integer;
  821. const
  822. CAAShift = 8;
  823. CAANum = 1 shl CAAShift;
  824. CAAMask = CAANum - 1;
  825. CAA2Num = CAANum shl 1;
  826. CAA2Mask = CAA2Num - 1;
  827. begin
  828. Cover := SAR_9(Area);
  829. if Cover < 0 then
  830. Cover := -Cover;
  831. if FillMode = pfEvenOdd then
  832. begin
  833. Cover := Cover and CAA2Mask;
  834. if Cover > CAANum then
  835. Cover := CAA2Num - Cover;
  836. end;
  837. if Cover > CAAMask then
  838. Cover := CAAMask;
  839. Result := Cover;
  840. end;
  841. { TScanLine }
  842. constructor TScanLine.Create(MinX, MaxX: Integer);
  843. begin
  844. inherited Create;
  845. FMaxLen := MaxX - MinX + 2;
  846. GetMem(FCovers, FMaxLen * SizeOf(TColor32));
  847. GetMem(FStartPtrs, FMaxLen * SizeOf(PColor32));
  848. GetMem(FCounts, FMaxLen * SizeOf(Word));
  849. FLastX := $7FFF;
  850. FLastY := $7FFF;
  851. FMinX := MinX;
  852. FCurCount := FCounts;
  853. FCurStartPtr := FStartPtrs;
  854. FNumSpans := 0;
  855. end;
  856. destructor TScanLine.Destroy;
  857. begin
  858. FreeMem(FCounts);
  859. FreeMem(FStartPtrs);
  860. FreeMem(FCovers);
  861. inherited Destroy;
  862. end;
  863. procedure TScanLine.AddCell(X, Y: Integer; Cover: Cardinal);
  864. begin
  865. Dec(X, FMinX);
  866. FCovers[X] := TColor32(Cover);
  867. if X = FLastX + 1 then
  868. Inc(FCurCount^)
  869. else
  870. begin
  871. Inc(FCurCount);
  872. FCurCount^ := 1;
  873. Inc(FCurStartPtr);
  874. FCurStartPtr^ := PColor32(@FCovers[X]);
  875. Inc(FNumSpans);
  876. end;
  877. FLastX := X;
  878. FLastY := Y;
  879. end;
  880. procedure TScanLine.AddSpan(X, Y: Integer; Len, Cover: Cardinal);
  881. begin
  882. Dec(X, FMinX);
  883. FillLongWord(FCovers[X], Len, Cover);
  884. if X = FLastX + 1 then
  885. Inc(FCurCount^, Word(Len))
  886. else
  887. begin
  888. Inc(FCurCount);
  889. FCurCount^ := Word(Len);
  890. Inc(FCurStartPtr);
  891. FCurStartPtr^ := PColor32(@FCovers[X]);
  892. Inc(FNumSpans);
  893. end;
  894. FLastX := X + Integer(Len) - 1;
  895. FLastY := Y;
  896. end;
  897. function TScanLine.IsReady(Y: Integer): Integer;
  898. begin
  899. Result := Ord((FNumSpans <> 0) and ((Y xor FLastY) <> 0));
  900. end;
  901. procedure TScanLine.ResetSpans;
  902. begin
  903. FLastX := $7FFF;
  904. FLastY := $7FFF;
  905. FCurCount := FCounts;
  906. FCurStartPtr := FStartPtrs;
  907. FNumSpans := 0;
  908. end;
  909. { TOutline }
  910. constructor TOutline.Create;
  911. begin
  912. inherited Create;
  913. FCurCellPtr := nil;
  914. FMin.X := $7FFFFFFF;
  915. FMin.Y := $7FFFFFFF;
  916. FMax.X := -$7FFFFFFF;
  917. FMax.Y := -$7FFFFFFF;
  918. FFlags := [ofSortRequired];
  919. SetCell(FCurCell, $7FFF, $7FFF);
  920. end;
  921. destructor TOutline.Destroy;
  922. var
  923. Ptr: PPCell;
  924. begin
  925. FreeMem(FSortedCells);
  926. if FNumBlocks <> 0 then
  927. begin
  928. Ptr := PPCell(NativeUInt(FCells) + (FNumBlocks - 1) * SizeOf(PCell));
  929. while FNumBlocks <> 0 do
  930. begin
  931. FreeMem(Ptr^);
  932. Dec(Ptr);
  933. Dec(FNumBlocks);
  934. end;
  935. FreeMem(FCells);
  936. end;
  937. inherited Destroy;
  938. end;
  939. procedure TOutline.Reset;
  940. begin
  941. FNumCells := 0;
  942. FCurBlock := 0;
  943. InternalReset;
  944. end;
  945. procedure TOutline.InternalReset;
  946. begin
  947. FMin.X := $7FFFFFFF;
  948. FMin.Y := $7FFFFFFF;
  949. FMax.X := -$7FFFFFFF;
  950. FMax.Y := -$7FFFFFFF;
  951. FFlags := [ofSortRequired];
  952. SetCell(FCurCell, $7FFF, $7FFF);
  953. end;
  954. procedure TOutline.AddCurCell;
  955. begin
  956. if FCurCell.Area or FCurCell.Cover <> 0 then
  957. begin
  958. if FNumCells and CCellBlockMask = 0 then
  959. begin
  960. if FNumBlocks >= CCellBlockLimit then
  961. Exit;
  962. AllocateBlock;
  963. end;
  964. FCurCellPtr^ := FCurCell;
  965. Inc(FCurCellPtr);
  966. Inc(FNumCells);
  967. end;
  968. end;
  969. procedure TOutline.AllocateBlock;
  970. var
  971. NewCells: PPCell;
  972. begin
  973. if FCurBlock >= FNumBlocks then
  974. begin
  975. if FNumBlocks >= FMaxBlocks then
  976. begin
  977. GetMem(NewCells, (FMaxBlocks + CCellBlockPool) * SizeOf(PCell));
  978. if Assigned(FCells) then
  979. begin
  980. Move(FCells^, NewCells^, FMaxBlocks * SizeOf(PCell));
  981. FreeMem(FCells);
  982. end;
  983. FCells := NewCells;
  984. Inc(FMaxBlocks, CCellBlockPool);
  985. end;
  986. GetMem(PPCell(NativeUInt(FCells) + FNumBlocks * SizeOf(PCell))^,
  987. Cardinal(CCellBlockSize) * SizeOf(TCell));
  988. Inc(FNumBlocks);
  989. end;
  990. FCurCellPtr := PPCell(NativeUInt(FCells) + FCurBlock * SizeOf(PCell))^;
  991. Inc(FCurBlock);
  992. end;
  993. function TOutline.GetCells: PPCell;
  994. begin
  995. if ofNotClosed in FFlags then
  996. begin
  997. LineTo(FClose.X, FClose.Y);
  998. FFlags := FFlags - [ofNotClosed];
  999. end;
  1000. // Perform sort only the first time.
  1001. if ofSortRequired in FFlags then
  1002. begin
  1003. AddCurCell;
  1004. if FNumCells = 0 then
  1005. begin
  1006. Result := nil;
  1007. Exit;
  1008. end;
  1009. SortCells;
  1010. FFlags := FFlags - [ofSortRequired];
  1011. end;
  1012. Result := FSortedCells;
  1013. end;
  1014. procedure TOutline.LineTo(X, Y: Integer);
  1015. var
  1016. C: Integer;
  1017. begin
  1018. if (ofSortRequired in FFlags) and (((FCur.X xor X) or (FCur.Y xor Y)) <> 0) then
  1019. begin
  1020. C := SAR_8(FCur.X);
  1021. if C < FMin.X then FMin.X := C;
  1022. Inc(C);
  1023. if C > FMax.X then FMax.X := C;
  1024. C := SAR_8(X);
  1025. if C < FMin.X then FMin.X := C;
  1026. Inc(C);
  1027. if C > FMax.X then FMax.X := C;
  1028. RenderLine(FCur.X, FCur.Y, X, Y);
  1029. FCur.X := X;
  1030. FCur.Y := Y;
  1031. FFlags := FFlags + [ofNotClosed];
  1032. end;
  1033. end;
  1034. procedure TOutline.MoveTo(X, Y: Integer);
  1035. begin
  1036. if not (ofSortRequired in FFlags) then //-7468, -6124, -6124, -4836
  1037. Reset;
  1038. if ofNotClosed in FFlags then
  1039. LineTo(FClose.X, FClose.Y);
  1040. SetCurCell(SAR_8(X), SAR_8(Y));
  1041. FCur.X := X;
  1042. FClose.X := X;
  1043. FCur.Y := Y;
  1044. FClose.Y := Y;
  1045. end;
  1046. procedure TOutline.RenderLine(X1, Y1, X2, Y2: Integer);
  1047. var
  1048. EY1, EY2, FY1, FY2, Dx, Dy, XFrom, XTo, P, Rem, AMod, Lift: Integer;
  1049. Delta, First, Incr, EX, TwoFx, Area: Integer;
  1050. begin
  1051. EY1 := SAR_8(Y1);
  1052. EY2 := SAR_8(Y2);
  1053. FY1 := Y1 and CPolyBaseMask;
  1054. FY2 := Y2 and CPolyBaseMask;
  1055. if EY1 < FMin.Y then FMin.Y := EY1;
  1056. if EY1 >= FMax.Y then FMax.Y := EY1 + 1;
  1057. if EY2 < FMin.Y then FMin.Y := EY2;
  1058. if EY2 >= FMax.Y then FMax.Y := EY2 + 1;
  1059. Dx := X2 - X1;
  1060. Dy := Y2 - Y1;
  1061. // everything is on a single scanline
  1062. if EY1 = EY2 then
  1063. begin
  1064. RenderScanLine(EY1, X1, FY1, X2, FY2);
  1065. Exit;
  1066. end;
  1067. // Vertical line - we have to calculate start and end cells, and then -
  1068. // the common values of the area and coverage for all cells of the line.
  1069. // We know exactly there's only one cell, so, we don't have to call
  1070. // RenderScanline().
  1071. Incr := 1;
  1072. if Dx = 0 then
  1073. begin
  1074. EX := SAR_8(X1);
  1075. TwoFx := (X1 - (EX shl CPolyBaseShift)) shl 1;
  1076. First := CPolyBaseSize;
  1077. if Dy < 0 then
  1078. begin
  1079. First := 0;
  1080. Incr := -1;
  1081. end;
  1082. Delta := First - FY1;
  1083. Inc(FCurCell.Cover, Delta);
  1084. Inc(FCurCell.Area, TwoFx * Delta);
  1085. Inc(EY1, Incr);
  1086. SetCurCell(EX, EY1);
  1087. Delta := First + First - CPolyBaseSize;
  1088. Area := TwoFx * Delta;
  1089. while EY1 <> EY2 do
  1090. begin
  1091. FCurCell.Cover := Delta;
  1092. FCurCell.Area := Area;
  1093. Inc(EY1, Incr);
  1094. SetCurCell(EX, EY1);
  1095. end;
  1096. Delta := FY2 - CPolyBaseSize + First;
  1097. Inc(FCurCell.Cover, Delta);
  1098. Inc(FCurCell.Area, TwoFx * Delta);
  1099. Exit;
  1100. end;
  1101. // ok, we have to render several scanlines
  1102. P := (CPolyBaseSize - FY1) * Dx;
  1103. First := CPolyBaseSize;
  1104. if Dy < 0 then
  1105. begin
  1106. P := FY1 * Dx;
  1107. First := 0;
  1108. Incr := -1;
  1109. Dy := -Dy;
  1110. end;
  1111. Delta := P div Dy;
  1112. AMod := P mod Dy;
  1113. if AMod < 0 then
  1114. begin
  1115. Dec(Delta);
  1116. Inc(AMod, Dy);
  1117. end;
  1118. XFrom := X1 + Delta;
  1119. RenderScanLine(EY1, X1, FY1, XFrom, First);
  1120. Inc(EY1, Incr);
  1121. SetCurCell(SAR_8(XFrom), EY1);
  1122. if EY1 <> EY2 then
  1123. begin
  1124. P := CPolyBaseSize * Dx;
  1125. Lift := P div Dy;
  1126. Rem := P mod Dy;
  1127. if Rem < 0 then
  1128. begin
  1129. Dec(Lift);
  1130. Inc(Rem, Dy);
  1131. end;
  1132. Dec(AMod, Dy);
  1133. while EY1 <> EY2 do
  1134. begin
  1135. Delta := Lift;
  1136. Inc(AMod, Rem);
  1137. if AMod >= 0 then
  1138. begin
  1139. Dec(AMod, Dy);
  1140. Inc(Delta);
  1141. end;
  1142. XTo := XFrom + Delta;
  1143. RenderScanLine(EY1, XFrom, CPolyBaseSize - First, XTo, First);
  1144. XFrom := XTo;
  1145. Inc(EY1, Incr);
  1146. SetCurCell(SAR_8(XFrom), EY1);
  1147. end;
  1148. end;
  1149. RenderScanLine(EY1, XFrom, CPolyBaseSize - First, X2, FY2);
  1150. end;
  1151. procedure TOutline.RenderScanLine(EY, X1, Y1, X2, Y2: Integer);
  1152. var
  1153. EX1, EX2, FX1, FX2, Delta, P, First, Dx, Incr, Lift, AMod, Rem: Integer;
  1154. begin
  1155. EX1 := SAR_8(X1);
  1156. EX2 := SAR_8(X2);
  1157. FX1 := X1 and CPolyBaseMask;
  1158. FX2 := X2 and CPolyBaseMask;
  1159. // trivial case. Happens often
  1160. if Y1 = Y2 then
  1161. begin
  1162. SetCurCell(EX2, EY);
  1163. Exit;
  1164. end;
  1165. // everything is located in a single cell. That is easy!
  1166. if EX1 = EX2 then
  1167. begin
  1168. Delta := Y2 - Y1;
  1169. Inc(FCurCell.Cover, Delta);
  1170. Inc(FCurCell.Area, (FX1 + FX2) * Delta);
  1171. Exit;
  1172. end;
  1173. // ok, we'll have to render a run of adjacent cells on the same scanline...
  1174. P := (CPolyBaseSize - FX1) * (Y2 - Y1);
  1175. First := CPolyBaseSize;
  1176. Incr := 1;
  1177. Dx := X2 - X1;
  1178. if Dx < 0 then
  1179. begin
  1180. P := FX1 * (Y2 - Y1);
  1181. First := 0;
  1182. Incr := -1;
  1183. Dx := -Dx;
  1184. end;
  1185. Delta := P div Dx;
  1186. AMod := P mod Dx;
  1187. if AMod < 0 then
  1188. begin
  1189. Dec(Delta);
  1190. Inc(AMod, Dx);
  1191. end;
  1192. Inc(FCurCell.Cover, Delta);
  1193. Inc(FCurCell.Area, (FX1 + First) * Delta);
  1194. Inc(EX1, Incr);
  1195. SetCurCell(EX1, EY);
  1196. Inc(Y1, Delta);
  1197. if EX1 <> EX2 then
  1198. begin
  1199. P := CPolyBaseSize * (Y2 - Y1 + Delta);
  1200. Lift := P div Dx;
  1201. Rem := P mod Dx;
  1202. if Rem < 0 then
  1203. begin
  1204. Dec(Lift);
  1205. Inc(Rem, Dx);
  1206. end;
  1207. Dec(AMod, Dx);
  1208. while EX1 <> EX2 do
  1209. begin
  1210. Delta := Lift;
  1211. Inc(AMod, Rem);
  1212. if AMod >= 0 then
  1213. begin
  1214. Dec(AMod, Dx);
  1215. Inc(Delta);
  1216. end;
  1217. Inc(FCurCell.Cover, Delta);
  1218. Inc(FCurCell.Area, CPolyBaseSize * Delta);
  1219. Inc(Y1, Delta);
  1220. Inc(EX1, Incr);
  1221. SetCurCell(EX1, EY);
  1222. end;
  1223. end;
  1224. Delta := Y2 - Y1;
  1225. Inc(FCurCell.Cover, Delta);
  1226. Inc(FCurCell.Area, (FX2 + CPolyBaseSize - First) * Delta);
  1227. end;
  1228. procedure TOutline.SetCurCell(X, Y: Integer);
  1229. begin
  1230. if FCurCell.PackedCoord <> (Y shl 16) + X then
  1231. begin
  1232. AddCurCell;
  1233. SetCell(FCurCell, X, Y);
  1234. end;
  1235. end;
  1236. procedure TOutline.SortCells;
  1237. var
  1238. SortedPtr, BlockPtr: PPCell;
  1239. CellPtr: PCell;
  1240. NB, I: Cardinal;
  1241. begin
  1242. if FNumCells = 0 then
  1243. Exit;
  1244. if FNumCells > FSortedSize then
  1245. begin
  1246. FreeMem(FSortedCells);
  1247. FSortedSize := FNumCells;
  1248. GetMem(FSortedCells, (FNumCells + 1) * SizeOf(PCell));
  1249. end;
  1250. SortedPtr := FSortedCells;
  1251. BlockPtr := FCells;
  1252. NB := FNumCells shr CCellBlockShift;
  1253. while NB <> 0 do
  1254. begin
  1255. Dec(NB);
  1256. CellPtr := BlockPtr^;
  1257. Inc(BlockPtr);
  1258. I := CCellBlockSize;
  1259. while I <> 0 do
  1260. begin
  1261. Dec(I);
  1262. SortedPtr^ := CellPtr;
  1263. Inc(SortedPtr);
  1264. Inc(CellPtr);
  1265. end;
  1266. end;
  1267. CellPtr := BlockPtr^;
  1268. I := FNumCells and CCellBlockMask;
  1269. while I <> 0 do
  1270. begin
  1271. Dec(I);
  1272. SortedPtr^ := CellPtr;
  1273. Inc(SortedPtr);
  1274. Inc(CellPtr);
  1275. end;
  1276. PPCell(NativeUInt(FSortedCells) + FNumCells * SizeOf(PCell))^ := nil;
  1277. QSortCells(FSortedCells, FNumCells);
  1278. end;
  1279. { TPolygonRenderer32AggLite }
  1280. procedure TPolygonRenderer32AggLite.Render(CellsPtr: Pointer; MinX, MaxX: Integer);
  1281. var
  1282. X, Y, Cover, Alpha, Area, Coord: Integer;
  1283. Cells: PPCell absolute CellsPtr;
  1284. CurCell, StartCell: PCell;
  1285. ScanLine: TScanLine;
  1286. procedure RenderSpan;
  1287. var
  1288. NumSpans: Cardinal;
  1289. BaseX: Integer;
  1290. Row: PColor32Array;
  1291. CurX: Integer;
  1292. Covers: PColor32;
  1293. NumPix: Integer;
  1294. BaseCovers: Pointer;
  1295. CurCount: PWord;
  1296. CurStartPtr: PPColor32;
  1297. begin
  1298. NumSpans := ScanLine.NumSpans;
  1299. BaseX := ScanLine.BaseX;
  1300. Row := Bitmap.ScanLine[ScanLine.Y];
  1301. BaseCovers := ScanLine.CoversPtr;
  1302. CurCount := ScanLine.CountsPtr;
  1303. CurStartPtr := ScanLine.StartPtrs;
  1304. if Assigned(Filler) then
  1305. repeat
  1306. Dec(NumSpans);
  1307. Inc(CurCount);
  1308. Inc(CurStartPtr);
  1309. CurX := (NativeInt(CurStartPtr^) - NativeInt(BaseCovers)) div SizeOf(TColor32) + BaseX;
  1310. Covers := CurStartPtr^;
  1311. NumPix := CurCount^;
  1312. if CurX < 0 then
  1313. begin
  1314. Inc(NumPix, CurX);
  1315. if NumPix <= 0 then
  1316. Continue;
  1317. Dec(Covers, CurX);
  1318. CurX := 0;
  1319. end;
  1320. if CurX + NumPix >= Bitmap.Width then
  1321. begin
  1322. NumPix := Bitmap.Width - CurX;
  1323. if NumPix <= 0 then
  1324. Continue;
  1325. end;
  1326. Filler.FillLine(@Row^[CurX], CurX, ScanLine.Y, NumPix, Covers, Bitmap.CombineMode);
  1327. until NumSpans = 0
  1328. else
  1329. repeat
  1330. Dec(NumSpans);
  1331. Inc(CurCount);
  1332. Inc(CurStartPtr);
  1333. CurX := (NativeInt(CurStartPtr^) - NativeInt(BaseCovers)) div SizeOf(TColor32) + BaseX;
  1334. Covers := CurStartPtr^;
  1335. NumPix := CurCount^;
  1336. if CurX < 0 then
  1337. begin
  1338. Inc(NumPix, CurX);
  1339. if NumPix <= 0 then
  1340. Continue;
  1341. Dec(Covers, CurX);
  1342. CurX := 0;
  1343. end;
  1344. if CurX + NumPix >= Bitmap.Width then
  1345. begin
  1346. NumPix := Bitmap.Width - CurX;
  1347. if NumPix <= 0 then
  1348. Continue;
  1349. end;
  1350. FillSpan(@Row^[CurX], PColor32(Covers), NumPix, Color);
  1351. until NumSpans = 0;
  1352. end;
  1353. begin
  1354. ScanLine := TScanLine.Create(MinX, MaxX); // -32, 64
  1355. try
  1356. Cover := 0;
  1357. CurCell := Cells^;
  1358. Inc(Cells);
  1359. while True do
  1360. begin
  1361. StartCell := CurCell;
  1362. Coord := CurCell^.Pnt.PackedCoord;
  1363. X := CurCell^.Pnt.X;
  1364. Y := CurCell^.Pnt.Y;
  1365. Area := StartCell^.Area;
  1366. Inc(Cover, StartCell^.Cover);
  1367. CurCell := Cells^;
  1368. Inc(Cells);
  1369. while Assigned(CurCell) do
  1370. begin
  1371. if CurCell^.Pnt.PackedCoord <> Coord then
  1372. Break;
  1373. Inc(Area, CurCell^.Area);
  1374. Inc(Cover, CurCell^.Cover);
  1375. CurCell := Cells^;
  1376. Inc(Cells);
  1377. end;
  1378. if Area <> 0 then
  1379. begin
  1380. Alpha := CalculateAlpha(Fillmode, (Cover shl (CPolyBaseShift + 1)) - Area);
  1381. if Alpha <> 0 then
  1382. begin
  1383. if ScanLine.IsReady(Y) <> 0 then
  1384. begin
  1385. if (ScanLine.Y >= 0) and (ScanLine.Y < Bitmap.Height) then
  1386. RenderSpan;
  1387. ScanLine.ResetSpans;
  1388. end;
  1389. ScanLine.AddCell(X, Y, GAMMA_ENCODING_TABLE[Alpha]);
  1390. end;
  1391. Inc(X);
  1392. end;
  1393. if not Assigned(CurCell) then
  1394. Break;
  1395. if CurCell^.Pnt.X > X then
  1396. begin
  1397. Alpha := CalculateAlpha(Fillmode, Cover shl (CPolyBaseShift + 1));
  1398. if Alpha <> 0 then
  1399. begin
  1400. if ScanLine.IsReady(Y) <> 0 then
  1401. begin
  1402. if (ScanLine.Y >= 0) and (ScanLine.Y < Bitmap.Height) then
  1403. RenderSpan;
  1404. ScanLine.ResetSpans;
  1405. end;
  1406. ScanLine.AddSpan(X, Y, CurCell^.Pnt.X - X, GAMMA_ENCODING_TABLE[Alpha]);
  1407. end;
  1408. end;
  1409. end;
  1410. with ScanLine do
  1411. if (NumSpans <> 0) and (Y >= 0) and (Y < Bitmap.Height) then
  1412. RenderSpan;
  1413. finally
  1414. ScanLine.Free;
  1415. end;
  1416. end;
  1417. type
  1418. TBitmap32Access = class(TBitmap32);
  1419. procedure TPolygonRenderer32AggLite.PolygonFS(
  1420. const Points: TArrayOfFloatPoint; const ClipRect: TFloatRect);
  1421. var
  1422. I: Integer;
  1423. Cells: PPCell;
  1424. OutLine: TOutline;
  1425. APoints: TArrayOfFloatPoint;
  1426. R: TFloatRect;
  1427. begin
  1428. R := ClipRect;
  1429. GR32.InflateRect(R, 0.05, 0.05);
  1430. APoints := ClipPolygon (Points, R);
  1431. OutLine := TOutline.Create;
  1432. try
  1433. OutLine.Reset;
  1434. OutLine.MoveTo(Fixed8(APoints[0].X), Fixed8(APoints[0].Y));
  1435. for I := 1 to High(APoints) do
  1436. OutLine.LineTo(Fixed8(APoints[I].X), Fixed8(APoints[I].Y));
  1437. // get cells and check count
  1438. Cells := OutLine.Cells;
  1439. if OutLine.NumCells = 0 then
  1440. Exit;
  1441. if Assigned(Filler) then
  1442. begin
  1443. // call begin rendering of assigned filler
  1444. Filler.BeginRendering;
  1445. Render(Cells, OutLine.MinX, OutLine.MaxX);
  1446. // rendering done, call end rendering of assigned filler
  1447. Filler.EndRendering;
  1448. end
  1449. else
  1450. Render(Cells, OutLine.MinX, OutLine.MaxX);
  1451. {$IFDEF CHANGENOTIFICATIONS}
  1452. if TBitmap32Access(Bitmap).UpdateCount = 0 then
  1453. if Length(APoints) > 0 then
  1454. Bitmap.Changed(MakeRect(OutLine.MinX, OutLine.MinY, OutLine.MaxX,
  1455. OutLine.MaxY));
  1456. {$ENDIF}
  1457. finally
  1458. SetLength(APoints, 0);
  1459. OutLine.Free;
  1460. end;
  1461. end;
  1462. procedure TPolygonRenderer32AggLite.PolyPolygonFS(
  1463. const Points: TArrayOfArrayOfFloatPoint; const ClipRect: TFloatRect);
  1464. var
  1465. I, J: Integer;
  1466. Cells: PPCell;
  1467. OutLine: TOutline;
  1468. Bounds: TRect;
  1469. APoints: TArrayOfArrayOfFloatPoint;
  1470. R: TFloatRect;
  1471. FirstValid: integer;
  1472. begin
  1473. if Length(Points) = 0 then
  1474. Exit;
  1475. APoints := Points;
  1476. // temporary fix for floating point rounding errors - corr. - to + by pws
  1477. R := ClipRect;
  1478. GR32.InflateRect(R, 0.05, 0.05);
  1479. FirstValid := -1;
  1480. for i := 0 to High(APoints) do
  1481. begin
  1482. APoints[i] := ClipPolygon(Points[I], R);
  1483. if (FirstValid = -1) and (Length(APoints[i]) > 0) then
  1484. FirstValid := i;
  1485. end;
  1486. if (FirstValid = -1) then
  1487. exit; // All were clipped
  1488. OutLine := TOutline.Create;
  1489. try
  1490. OutLine.Reset;
  1491. OutLine.MoveTo(Fixed8(APoints[FirstValid, 0].X), Fixed8(APoints[FirstValid, 0].Y));
  1492. for I := 1 to High(APoints[FirstValid]) do
  1493. OutLine.LineTo(Fixed8(APoints[FirstValid, I].X), Fixed8(APoints[FirstValid, I].Y));
  1494. Bounds := MakeRect(OutLine.MinX, OutLine.MinY, OutLine.MaxX, OutLine.MaxY);
  1495. for J := FirstValid+1 to High(APoints) do
  1496. begin
  1497. if (Length(APoints[J]) = 0) then
  1498. continue;
  1499. OutLine.MoveTo(Fixed8(APoints[J, 0].X), Fixed8(APoints[J, 0].Y));
  1500. for I := 1 to High(APoints[J]) do
  1501. OutLine.LineTo(Fixed8(APoints[J, I].X), Fixed8(APoints[J, I].Y));
  1502. Bounds.Left := Min(Bounds.Left, OutLine.MinX);
  1503. Bounds.Right := Max(Bounds.Right, OutLine.MaxX);
  1504. Bounds.Top := Min(Bounds.Top, OutLine.MinY);
  1505. Bounds.Bottom := Max(Bounds.Bottom, OutLine.MaxY);
  1506. end;
  1507. // get cells and check count
  1508. Cells := OutLine.Cells;
  1509. if OutLine.NumCells = 0 then
  1510. Exit;
  1511. if Assigned(Filler) then
  1512. begin
  1513. // call begin rendering of assigned filler
  1514. Filler.BeginRendering;
  1515. Render(Cells, Bounds.Left, Bounds.Right);
  1516. // rendering done, call end rendering of assigned filler
  1517. Filler.EndRendering;
  1518. end
  1519. else
  1520. Render(Cells, Bounds.Left, Bounds.Right);
  1521. {$IFDEF CHANGENOTIFICATIONS}
  1522. if TBitmap32Access(Bitmap).UpdateCount = 0 then
  1523. for I := 0 to High(APoints) do
  1524. if Length(APoints[I]) > 0 then
  1525. Bitmap.Changed(Bounds);
  1526. {$ENDIF}
  1527. finally
  1528. OutLine.Free;
  1529. SetLength(APoints, 0);
  1530. end;
  1531. end;
  1532. var
  1533. FillSpanRegistry: TFunctionRegistry;
  1534. procedure RegisterBindings;
  1535. begin
  1536. FillSpanRegistry := NewRegistry('GR32_PolygonsAggLite bindings');
  1537. FillSpanRegistry.RegisterBinding(@@FILLSPAN, 'FILLSPAN');
  1538. // pure pascal
  1539. FillSpanRegistry[@@FILLSPAN].Add(@FILLSPAN_Pas, [isPascal]).Name := 'FILLSPAN_Pas';
  1540. {$if defined(TARGET_x86)} // ASM & SSE2 implementations appears to be broken on x64. Fails with AV.
  1541. {$IFNDEF PUREPASCAL}
  1542. FillSpanRegistry[@@FILLSPAN].Add(@FILLSPAN_ASM, [isAssembler]).Name := 'FILLSPAN_ASM';
  1543. {$IFNDEF OMIT_SSE2}
  1544. FillSpanRegistry[@@FILLSPAN].Add(@FILLSPAN_SSE2, [isSSE2]).Name := 'FILLSPAN_SSE2';
  1545. {$ENDIF}
  1546. {$ENDIF}
  1547. {$ifend}
  1548. FillSpanRegistry.RebindAll;
  1549. end;
  1550. initialization
  1551. RegisterPolygonRenderer(TPolygonRenderer32AggLite);
  1552. RegisterBindings;
  1553. finalization
  1554. end.