GR32_Brushes.pas 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749
  1. unit GR32_Brushes;
  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 Vectorial Polygon Rasterizer for Graphics32
  23. *
  24. * The Initial Developer of the Original Code is
  25. * Mattias Andersson <[email protected]>
  26. *
  27. * Portions created by the Initial Developer are Copyright (C) 2012
  28. * the Initial Developer. All Rights Reserved.
  29. *
  30. * ***** END LICENSE BLOCK ***** *)
  31. interface
  32. {$include GR32.inc}
  33. {-$define GR32_DEBUG_BRUSH}
  34. uses
  35. Classes, GR32, GR32_Polygons, GR32_Transforms;
  36. type
  37. TBooleanArray = array of boolean;
  38. type
  39. TCustomBrush = class;
  40. TBrushClass = class of TCustomBrush;
  41. // TODO: devise a common base class for TBrushCollection/TLayerCollection
  42. { TBrushCollection }
  43. TBrushCollection = class(TNotifiablePersistent)
  44. strict private
  45. FItems: TList;
  46. FOwner: TPersistent;
  47. function GetCount: Integer;
  48. function GetItem(Index: Integer): TCustomBrush;
  49. procedure SetItem(Index: Integer; const Value: TCustomBrush);
  50. protected
  51. procedure InsertItem(Item: TCustomBrush);
  52. procedure RemoveItem(Item: TCustomBrush);
  53. procedure MoveItem(OldIndex, NewIndex: integer);
  54. public
  55. constructor Create(AOwner: TPersistent);
  56. destructor Destroy; override;
  57. function Add(ItemClass: TBrushClass): TCustomBrush;
  58. procedure Clear;
  59. procedure Delete(Index: Integer);
  60. function Insert(Index: Integer; ItemClass: TBrushClass): TCustomBrush;
  61. function IndexOf(Item: TCustomBrush): integer;
  62. property Owner: TPersistent read FOwner;
  63. property Count: Integer read GetCount;
  64. property Items[Index: Integer]: TCustomBrush read GetItem write SetItem; default;
  65. end;
  66. { TCustomBrush }
  67. TCustomBrush = class(TNotifiablePersistent)
  68. strict private
  69. FBrushCollection: TBrushCollection;
  70. FVisible: Boolean;
  71. FBatchCount: integer;
  72. function GetIndex: Integer;
  73. procedure SetBrushCollection(const Value: TBrushCollection);
  74. procedure SetVisible(const Value: Boolean);
  75. protected
  76. procedure SetIndex(Value: Integer); virtual;
  77. procedure UpdateRenderer(Renderer: TCustomPolygonRenderer); virtual;
  78. function ProcessPolyPolygon(Renderer: TCustomPolygonRenderer; const Points: TArrayOfArrayOfFloatPoint;
  79. const ClipRect: TFloatRect; Transformation: TTransformation; Closed: Boolean): TArrayOfArrayOfFloatPoint; virtual;
  80. procedure RenderPolyPolygon(Renderer: TCustomPolygonRenderer; const Points: TArrayOfArrayOfFloatPoint;
  81. const ClipRect: TFloatRect; Transformation: TTransformation); virtual;
  82. procedure BeginPolygon; virtual;
  83. procedure EndPolygon(Renderer: TCustomPolygonRenderer; const Points: TArrayOfArrayOfFloatPoint;
  84. const ClipRect: TFloatRect; Transformation: TTransformation); virtual;
  85. public
  86. constructor Create(ABrushCollection: TBrushCollection); virtual;
  87. destructor Destroy; override;
  88. procedure Changed; override;
  89. // Single polygon, either open or closed
  90. procedure PolygonFS(Renderer: TCustomPolygonRenderer; const Points: TArrayOfFloatPoint;
  91. const ClipRect: TFloatRect; Transformation: TTransformation; Closed: Boolean); virtual;
  92. // Polypolygons, either all open or all closed
  93. procedure PolyPolygonFS(Renderer: TCustomPolygonRenderer; const Points: TArrayOfArrayOfFloatPoint;
  94. const ClipRect: TFloatRect; Transformation: TTransformation; Closed: Boolean); virtual;
  95. // Polypolygons, individually open or closed
  96. procedure PolyPolygonMixedFS(Renderer: TCustomPolygonRenderer; const Points: TArrayOfArrayOfFloatPoint;
  97. const ClipRect: TFloatRect; Transformation: TTransformation; Closed: TBooleanArray); virtual;
  98. property Index: Integer read GetIndex write SetIndex;
  99. property BrushCollection: TBrushCollection read FBrushCollection write SetBrushCollection;
  100. property Visible: Boolean read FVisible write SetVisible;
  101. end;
  102. { TSolidBrush }
  103. TSolidBrush = class(TCustomBrush)
  104. strict private
  105. FFillColor: TColor32;
  106. FFillMode: TPolyFillMode;
  107. FFiller: TCustomPolygonFiller;
  108. procedure SetFillColor(const Value: TColor32);
  109. procedure SetFillMode(const Value: TPolyFillMode);
  110. procedure SetFiller(const Value: TCustomPolygonFiller);
  111. protected
  112. procedure UpdateRenderer(Renderer: TCustomPolygonRenderer); override;
  113. public
  114. constructor Create(ABrushCollection: TBrushCollection); override;
  115. property FillColor: TColor32 read FFillColor write SetFillColor;
  116. property FillMode: TPolyFillMode read FFillMode write SetFillMode;
  117. property Filler: TCustomPolygonFiller read FFiller write SetFiller;
  118. end;
  119. { TNestedBrush }
  120. TNestedBrush = class(TSolidBrush)
  121. strict private
  122. FBrushes: TBrushCollection;
  123. public
  124. constructor Create(ABrushCollection: TBrushCollection); override;
  125. destructor Destroy; override;
  126. procedure PolygonFS(Renderer: TCustomPolygonRenderer; const Points: TArrayOfFloatPoint;
  127. const ClipRect: TFloatRect; Transformation: TTransformation; Closed: Boolean); override;
  128. procedure PolyPolygonFS(Renderer: TCustomPolygonRenderer; const Points: TArrayOfArrayOfFloatPoint;
  129. const ClipRect: TFloatRect; Transformation: TTransformation; Closed: Boolean); override;
  130. procedure PolyPolygonMixedFS(Renderer: TCustomPolygonRenderer; const Points: TArrayOfArrayOfFloatPoint;
  131. const ClipRect: TFloatRect; Transformation: TTransformation; Closed: TBooleanArray); override;
  132. property Brushes: TBrushCollection read FBrushes;
  133. end;
  134. { TStrokeBrush }
  135. TStrokeBrush = class(TSolidBrush)
  136. strict private
  137. FStrokeWidth: TFloat;
  138. FJoinStyle: TJoinStyle;
  139. FMiterLimit: TFloat;
  140. FEndStyle: TEndStyle;
  141. procedure SetStrokeWidth(const Value: TFloat);
  142. procedure SetEndStyle(const Value: TEndStyle);
  143. procedure SetJoinStyle(const Value: TJoinStyle);
  144. procedure SetMiterLimit(const Value: TFloat);
  145. protected
  146. function ProcessPolyPolygon(Renderer: TCustomPolygonRenderer; const Points: TArrayOfArrayOfFloatPoint;
  147. const ClipRect: TFloatRect; Transformation: TTransformation; Closed: Boolean): TArrayOfArrayOfFloatPoint; override;
  148. public
  149. constructor Create(BrushCollection: TBrushCollection); override;
  150. property StrokeWidth: TFloat read FStrokeWidth write SetStrokeWidth;
  151. property JoinStyle: TJoinStyle read FJoinStyle write SetJoinStyle;
  152. property EndStyle: TEndStyle read FEndStyle write SetEndStyle;
  153. property MiterLimit: TFloat read FMiterLimit write SetMiterLimit;
  154. end;
  155. { TGrowBrush }
  156. TGrowBrush = class(TNestedBrush)
  157. strict private
  158. FGrowAmount: TFloat;
  159. FJoinStyle: TJoinStyle;
  160. FMiterLimit: TFloat;
  161. procedure SetGrowAmount(const Value: TFloat);
  162. procedure SetJoinStyle(const Value: TJoinStyle);
  163. procedure SetMiterLimit(const Value: TFloat);
  164. protected
  165. function ProcessPolyPolygon(Renderer: TCustomPolygonRenderer; const Points: TArrayOfArrayOfFloatPoint;
  166. const ClipRect: TFloatRect; Transformation: TTransformation; Closed: Boolean): TArrayOfArrayOfFloatPoint; override;
  167. public
  168. constructor Create(BrushCollection: TBrushCollection); override;
  169. property GrowAmount: TFloat read FGrowAmount write SetGrowAmount;
  170. property JoinStyle: TJoinStyle read FJoinStyle write SetJoinStyle;
  171. property MiterLimit: TFloat read FMiterLimit write SetMiterLimit;
  172. end;
  173. { TDashedBrush }
  174. TDashedBrush = class(TStrokeBrush)
  175. strict private
  176. FDashOffset: TFloat;
  177. FDashArray: TArrayOfFloat;
  178. procedure SetDashOffset(const Value: TFloat);
  179. procedure DoSetDashArray(const ADashArray: TArrayOfFloat); // TODO :Rename once SetDashArray is removed
  180. protected
  181. function ProcessPolyPolygon(Renderer: TCustomPolygonRenderer; const Points: TArrayOfArrayOfFloatPoint;
  182. const ClipRect: TFloatRect; Transformation: TTransformation; Closed: Boolean): TArrayOfArrayOfFloatPoint; override;
  183. public
  184. procedure SetDashArray(const ADashArray: TArrayOfFloat); deprecated 'Use DashArray property';
  185. property DashArray: TArrayOfFloat read FDashArray write DoSetDashArray;
  186. property DashOffset: TFloat read FDashOffset write SetDashOffset;
  187. end;
  188. implementation
  189. uses
  190. GR32_VectorUtils;
  191. { TBrushCollection }
  192. function TBrushCollection.Add(ItemClass: TBrushClass): TCustomBrush;
  193. begin
  194. Result := ItemClass.Create(Self);
  195. Result.Index := FItems.Count - 1;
  196. //Notify(lnLayerAdded, Result, Result.Index);
  197. end;
  198. procedure TBrushCollection.Clear;
  199. begin
  200. BeginUpdate;
  201. try
  202. while FItems.Count > 0 do TCustomBrush(FItems.Last).Free;
  203. //Notify(lnCleared, nil, 0);
  204. finally
  205. EndUpdate;
  206. end;
  207. end;
  208. constructor TBrushCollection.Create(AOwner: TPersistent);
  209. begin
  210. inherited Create;
  211. FOwner := AOwner;
  212. FItems := TList.Create;
  213. end;
  214. procedure TBrushCollection.Delete(Index: Integer);
  215. begin
  216. TCustomBrush(FItems[Index]).Free;
  217. end;
  218. destructor TBrushCollection.Destroy;
  219. begin
  220. if Assigned(FItems) then Clear;
  221. FItems.Free;
  222. inherited;
  223. end;
  224. function TBrushCollection.GetCount: Integer;
  225. begin
  226. Result := FItems.Count;
  227. end;
  228. function TBrushCollection.GetItem(Index: Integer): TCustomBrush;
  229. begin
  230. Result := FItems[Index];
  231. end;
  232. function TBrushCollection.IndexOf(Item: TCustomBrush): integer;
  233. begin
  234. Result := FItems.IndexOf(Item);
  235. end;
  236. function TBrushCollection.Insert(Index: Integer;
  237. ItemClass: TBrushClass): TCustomBrush;
  238. begin
  239. BeginUpdate;
  240. try
  241. Result := Add(ItemClass);
  242. Result.Index := Index;
  243. finally
  244. EndUpdate;
  245. end;
  246. end;
  247. procedure TBrushCollection.InsertItem(Item: TCustomBrush);
  248. begin
  249. BeginUpdate;
  250. try
  251. FItems.Add(Item);
  252. Changed;
  253. finally
  254. EndUpdate;
  255. end;
  256. end;
  257. procedure TBrushCollection.MoveItem(OldIndex, NewIndex: integer);
  258. begin
  259. FItems.Move(OldIndex, NewIndex);
  260. end;
  261. procedure TBrushCollection.RemoveItem(Item: TCustomBrush);
  262. var
  263. Index: Integer;
  264. begin
  265. Index := FItems.IndexOf(Item);
  266. if (Index < 0) then
  267. exit;
  268. BeginUpdate;
  269. try
  270. FItems.Delete(Index);
  271. Changed;
  272. finally
  273. EndUpdate;
  274. end;
  275. end;
  276. procedure TBrushCollection.SetItem(Index: Integer; const Value: TCustomBrush);
  277. begin
  278. TCollectionItem(FItems[Index]).Assign(Value);
  279. end;
  280. { TCustomBrush }
  281. constructor TCustomBrush.Create(ABrushCollection: TBrushCollection);
  282. begin
  283. inherited Create;
  284. BrushCollection := ABrushCollection;
  285. FVisible := True;
  286. end;
  287. destructor TCustomBrush.Destroy;
  288. begin
  289. SetBrushCollection(nil);
  290. inherited;
  291. end;
  292. procedure TCustomBrush.BeginPolygon;
  293. begin
  294. Assert(FBatchCount = 0);
  295. Inc(FBatchCount);
  296. end;
  297. procedure TCustomBrush.EndPolygon(Renderer: TCustomPolygonRenderer; const Points: TArrayOfArrayOfFloatPoint;
  298. const ClipRect: TFloatRect; Transformation: TTransformation);
  299. begin
  300. Assert(FBatchCount = 1);
  301. Dec(FBatchCount);
  302. RenderPolyPolygon(Renderer, Points, ClipRect, Transformation);
  303. end;
  304. procedure TCustomBrush.Changed;
  305. begin
  306. inherited;
  307. if (LockUpdateCount = 0) and (FBrushCollection <> nil) then
  308. FBrushCollection.Changed;
  309. end;
  310. function TCustomBrush.GetIndex: Integer;
  311. begin
  312. if (FBrushCollection <> nil) then
  313. Result := FBrushCollection.IndexOf(Self)
  314. else
  315. Result := -1;
  316. end;
  317. function TCustomBrush.ProcessPolyPolygon(Renderer: TCustomPolygonRenderer; const Points: TArrayOfArrayOfFloatPoint;
  318. const ClipRect: TFloatRect; Transformation: TTransformation; Closed: Boolean): TArrayOfArrayOfFloatPoint;
  319. begin
  320. Result := Points;
  321. end;
  322. procedure TCustomBrush.RenderPolyPolygon(Renderer: TCustomPolygonRenderer; const Points: TArrayOfArrayOfFloatPoint;
  323. const ClipRect: TFloatRect; Transformation: TTransformation);
  324. begin
  325. UpdateRenderer(Renderer);
  326. Renderer.PolyPolygonFS(Points, ClipRect, Transformation);
  327. {$ifdef GR32_DEBUG_BRUSH}
  328. PolyPolylineFS(TPolygonRenderer32(Renderer).Bitmap, Points, clBlue32, True);
  329. {$endif GR32_DEBUG_BRUSH}
  330. end;
  331. procedure TCustomBrush.PolygonFS(Renderer: TCustomPolygonRenderer; const Points: TArrayOfFloatPoint; const ClipRect: TFloatRect;
  332. Transformation: TTransformation; Closed: Boolean);
  333. begin
  334. PolyPolygonFS(Renderer, [Points], ClipRect, Transformation, Closed);
  335. end;
  336. procedure TCustomBrush.PolyPolygonFS(Renderer: TCustomPolygonRenderer; const Points: TArrayOfArrayOfFloatPoint;
  337. const ClipRect: TFloatRect; Transformation: TTransformation; Closed: Boolean);
  338. var
  339. Buffer: TArrayOfArrayOfFloatPoint;
  340. begin
  341. BeginPolygon;
  342. Buffer := ProcessPolyPolygon(Renderer, Points, ClipRect, Transformation, Closed);
  343. EndPolygon(Renderer, Buffer, ClipRect, Transformation);
  344. end;
  345. procedure TCustomBrush.PolyPolygonMixedFS(Renderer: TCustomPolygonRenderer; const Points: TArrayOfArrayOfFloatPoint;
  346. const ClipRect: TFloatRect; Transformation: TTransformation; Closed: TBooleanArray);
  347. var
  348. Start, Next: Integer;
  349. i: integer;
  350. Buffer: TArrayOfArrayOfFloatPoint;
  351. RunBuffer: TArrayOfArrayOfFloatPoint;
  352. RunClosed: boolean;
  353. begin
  354. if (Length(Points) = 0) then
  355. exit;
  356. // Assume some paths are closed, some are open
  357. BeginPolygon;
  358. begin
  359. Buffer := nil;
  360. Start := 0;
  361. // Find contiguous chunks of path with same "closedness"
  362. while (Start < Length(Points)) do
  363. begin
  364. RunClosed := Closed[Start];
  365. // Find a run of same "closedness"
  366. Next := Start+1;
  367. while (Next < Length(Points)) and (Closed[Next] = RunClosed) do
  368. Inc(Next);
  369. // Run goes from Start to Next-1
  370. SetLength(RunBuffer, Next-Start);
  371. i := 0;
  372. while (Start < Next) do
  373. begin
  374. RunBuffer[i] := Points[Start];
  375. Inc(Start);
  376. Inc(i);
  377. end;
  378. // Process this run
  379. Buffer := Buffer + ProcessPolyPolygon(Renderer, RunBuffer, ClipRect, Transformation, RunClosed);
  380. end;
  381. end;
  382. EndPolygon(Renderer, Buffer, ClipRect, Transformation);
  383. end;
  384. procedure TCustomBrush.SetBrushCollection(const Value: TBrushCollection);
  385. var
  386. OldBrushCollection: TBrushCollection;
  387. begin
  388. if FBrushCollection <> Value then
  389. begin
  390. OldBrushCollection := FBrushCollection;
  391. FBrushCollection := nil;
  392. if (OldBrushCollection <> nil) then
  393. OldBrushCollection.RemoveItem(Self);
  394. FBrushCollection := Value;
  395. if (FBrushCollection <> nil) then
  396. FBrushCollection.InsertItem(Self);
  397. end;
  398. end;
  399. procedure TCustomBrush.SetIndex(Value: Integer);
  400. var
  401. CurIndex: Integer;
  402. begin
  403. CurIndex := GetIndex;
  404. if (CurIndex < 0) or (CurIndex = Value) then
  405. exit;
  406. if (Value < 0) then
  407. Value := 0;
  408. if (Value >= BrushCollection.Count) then
  409. Value := BrushCollection.Count - 1;
  410. if (Value = CurIndex) then
  411. exit;
  412. if Visible then
  413. BrushCollection.BeginUpdate;
  414. try
  415. BrushCollection.MoveItem(CurIndex, Value);
  416. finally
  417. if Visible then
  418. BrushCollection.EndUpdate;
  419. end;
  420. end;
  421. procedure TCustomBrush.SetVisible(const Value: Boolean);
  422. begin
  423. if FVisible <> Value then
  424. begin
  425. FVisible := Value;
  426. Changed;
  427. end;
  428. end;
  429. procedure TCustomBrush.UpdateRenderer(Renderer: TCustomPolygonRenderer);
  430. begin
  431. end;
  432. { TNestedBrush }
  433. constructor TNestedBrush.Create(ABrushCollection: TBrushCollection);
  434. begin
  435. inherited;
  436. FBrushes := TBrushCollection.Create(Self);
  437. end;
  438. destructor TNestedBrush.Destroy;
  439. begin
  440. FBrushes.Free;
  441. inherited;
  442. end;
  443. procedure TNestedBrush.PolygonFS(Renderer: TCustomPolygonRenderer; const Points: TArrayOfFloatPoint;
  444. const ClipRect: TFloatRect; Transformation: TTransformation; Closed: Boolean);
  445. var
  446. I: Integer;
  447. begin
  448. for I := 0 to FBrushes.Count - 1 do
  449. if FBrushes[I].Visible then
  450. FBrushes[I].PolygonFS(Renderer, Points, ClipRect, Transformation, Closed);
  451. end;
  452. procedure TNestedBrush.PolyPolygonFS(Renderer: TCustomPolygonRenderer; const Points: TArrayOfArrayOfFloatPoint;
  453. const ClipRect: TFloatRect; Transformation: TTransformation; Closed: Boolean);
  454. var
  455. I: Integer;
  456. begin
  457. for I := 0 to FBrushes.Count - 1 do
  458. if FBrushes[I].Visible then
  459. FBrushes[I].PolyPolygonFS(Renderer, Points, ClipRect, Transformation, Closed);
  460. end;
  461. procedure TNestedBrush.PolyPolygonMixedFS(Renderer: TCustomPolygonRenderer; const Points: TArrayOfArrayOfFloatPoint;
  462. const ClipRect: TFloatRect; Transformation: TTransformation; Closed: TBooleanArray);
  463. var
  464. I: Integer;
  465. begin
  466. for I := 0 to FBrushes.Count - 1 do
  467. if FBrushes[I].Visible then
  468. FBrushes[I].PolyPolygonMixedFS(Renderer, Points, ClipRect, Transformation, Closed);
  469. end;
  470. { TSolidBrush }
  471. constructor TSolidBrush.Create(ABrushCollection: TBrushCollection);
  472. begin
  473. inherited;
  474. FFillColor := clBlack32;
  475. end;
  476. procedure TSolidBrush.SetFillColor(const Value: TColor32);
  477. begin
  478. if FFillColor <> Value then
  479. begin
  480. FFillColor := Value;
  481. Changed;
  482. end;
  483. end;
  484. procedure TSolidBrush.SetFiller(const Value: TCustomPolygonFiller);
  485. begin
  486. if FFiller <> Value then
  487. begin
  488. FFiller := Value;
  489. Changed;
  490. end;
  491. end;
  492. procedure TSolidBrush.SetFillMode(const Value: TPolyFillMode);
  493. begin
  494. if FFillMode <> Value then
  495. begin
  496. FFillMode := Value;
  497. Changed;
  498. end;
  499. end;
  500. procedure TSolidBrush.UpdateRenderer(Renderer: TCustomPolygonRenderer);
  501. var
  502. R: TPolygonRenderer32;
  503. begin
  504. R := Renderer as TPolygonRenderer32;
  505. R.Color := FillColor;
  506. R.FillMode := FillMode;
  507. R.Filler := Filler;
  508. end;
  509. { TStrokeBrush }
  510. constructor TStrokeBrush.Create(BrushCollection: TBrushCollection);
  511. begin
  512. inherited;
  513. BeginLockUpdate;
  514. FillMode := pfWinding;
  515. EndLockUpdate;
  516. FStrokeWidth := 1;
  517. FMiterLimit := DEFAULT_MITER_LIMIT;
  518. end;
  519. function TStrokeBrush.ProcessPolyPolygon(Renderer: TCustomPolygonRenderer; const Points: TArrayOfArrayOfFloatPoint;
  520. const ClipRect: TFloatRect; Transformation: TTransformation; Closed: Boolean): TArrayOfArrayOfFloatPoint;
  521. begin
  522. Result := BuildPolyPolyLine(Points, Closed, StrokeWidth, JoinStyle, EndStyle, MiterLimit);
  523. Result := inherited ProcessPolyPolygon(Renderer, Result, ClipRect, Transformation, True);
  524. {$ifdef GR32_DEBUG_BRUSH}
  525. PolyPolylineFS(TPolygonRenderer32(Renderer).Bitmap, Points, clRed32, Closed);
  526. {$endif GR32_DEBUG_BRUSH}
  527. end;
  528. procedure TStrokeBrush.SetEndStyle(const Value: TEndStyle);
  529. begin
  530. if FEndStyle <> Value then
  531. begin
  532. FEndStyle := Value;
  533. Changed;
  534. end;
  535. end;
  536. procedure TStrokeBrush.SetJoinStyle(const Value: TJoinStyle);
  537. begin
  538. if FJoinStyle <> Value then
  539. begin
  540. FJoinStyle := Value;
  541. Changed;
  542. end;
  543. end;
  544. procedure TStrokeBrush.SetMiterLimit(const Value: TFloat);
  545. begin
  546. if FMiterLimit <> Value then
  547. begin
  548. FMiterLimit := Value;
  549. Changed;
  550. end;
  551. end;
  552. procedure TStrokeBrush.SetStrokeWidth(const Value: TFloat);
  553. begin
  554. if FStrokeWidth <> Value then
  555. begin
  556. FStrokeWidth := Value;
  557. Changed;
  558. end;
  559. end;
  560. { TDashedBrush }
  561. procedure TDashedBrush.DoSetDashArray(const ADashArray: TArrayOfFloat);
  562. begin
  563. FDashArray := Copy(ADashArray);
  564. Changed;
  565. end;
  566. function TDashedBrush.ProcessPolyPolygon(Renderer: TCustomPolygonRenderer; const Points: TArrayOfArrayOfFloatPoint;
  567. const ClipRect: TFloatRect; Transformation: TTransformation; Closed: Boolean): TArrayOfArrayOfFloatPoint;
  568. var
  569. I: Integer;
  570. begin
  571. if (Length(FDashArray) > 0) then
  572. begin
  573. Result := nil;
  574. for I := 0 to High(Points) do
  575. Result := Result + BuildDashedLine(Points[I], FDashArray, FDashOffset, Closed);
  576. Result := inherited ProcessPolyPolygon(Renderer, Result, ClipRect, Transformation, False);
  577. end else
  578. Result := inherited ProcessPolyPolygon(Renderer, Points, ClipRect, Transformation, Closed);
  579. end;
  580. procedure TDashedBrush.SetDashArray(const ADashArray: TArrayOfFloat);
  581. begin
  582. DoSetDashArray(ADashArray);
  583. end;
  584. procedure TDashedBrush.SetDashOffset(const Value: TFloat);
  585. begin
  586. if FDashOffset <> Value then
  587. begin
  588. FDashOffset := Value;
  589. Changed;
  590. end;
  591. end;
  592. { TGrowBrush }
  593. constructor TGrowBrush.Create(BrushCollection: TBrushCollection);
  594. begin
  595. inherited;
  596. FMiterLimit := DEFAULT_MITER_LIMIT;
  597. end;
  598. function TGrowBrush.ProcessPolyPolygon(Renderer: TCustomPolygonRenderer; const Points: TArrayOfArrayOfFloatPoint;
  599. const ClipRect: TFloatRect; Transformation: TTransformation; Closed: Boolean): TArrayOfArrayOfFloatPoint;
  600. var
  601. I: Integer;
  602. begin
  603. SetLength(Result, Length(Points));
  604. for I := 0 to High(Points) do
  605. Result[I] := Grow(Points[I], GrowAmount, JoinStyle, Closed, MiterLimit);
  606. Result := inherited ProcessPolyPolygon(Renderer, Result, ClipRect, Transformation, Closed);
  607. end;
  608. procedure TGrowBrush.SetGrowAmount(const Value: TFloat);
  609. begin
  610. if FGrowAmount <> Value then
  611. begin
  612. FGrowAmount := Value;
  613. Changed;
  614. end;
  615. end;
  616. procedure TGrowBrush.SetJoinStyle(const Value: TJoinStyle);
  617. begin
  618. if FJoinStyle <> Value then
  619. begin
  620. FJoinStyle := Value;
  621. Changed;
  622. end;
  623. end;
  624. procedure TGrowBrush.SetMiterLimit(const Value: TFloat);
  625. begin
  626. if FMiterLimit <> Value then
  627. begin
  628. FMiterLimit := Value;
  629. Changed;
  630. end;
  631. end;
  632. end.