GR32_Brushes.pas 20 KB

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