source: trunk/Packages/Graphics32/GR32_Brushes.pas

Last change on this file was 2, checked in by chronos, 5 years ago
File size: 16.6 KB
Line 
1unit GR32_Brushes;
2
3(* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1 or LGPL 2.1 with linking exception
5 *
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
10 *
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
15 *
16 * Alternatively, the contents of this file may be used under the terms of the
17 * Free Pascal modified version of the GNU Lesser General Public License
18 * Version 2.1 (the "FPC modified LGPL License"), in which case the provisions
19 * of this license are applicable instead of those above.
20 * Please see the file LICENSE.txt for additional information concerning this
21 * license.
22 *
23 * The Original Code is Vectorial Polygon Rasterizer for Graphics32
24 *
25 * The Initial Developer of the Original Code is
26 * Mattias Andersson <mattias@centaurix.com>
27 *
28 * Portions created by the Initial Developer are Copyright (C) 2012
29 * the Initial Developer. All Rights Reserved.
30 *
31 * Contributor(s):
32 *
33 * ***** END LICENSE BLOCK ***** *)
34
35interface
36
37{$I GR32.inc}
38
39uses
40 Classes, GR32, GR32_Polygons, GR32_Transforms;
41
42type
43 TCustomBrush = class;
44 TBrushClass = class of TCustomBrush;
45
46// TODO: devise a common base class for TBrushCollection/TLayerCollection
47
48 { TBrushCollection }
49 TBrushCollection = class(TNotifiablePersistent)
50 private
51 FItems: TList;
52 FOwner: TPersistent;
53 procedure InsertItem(Item: TCustomBrush);
54 procedure RemoveItem(Item: TCustomBrush);
55 function GetCount: Integer;
56 function GetItem(Index: Integer): TCustomBrush;
57 procedure SetItem(Index: Integer; const Value: TCustomBrush);
58 public
59 constructor Create(AOwner: TPersistent);
60 destructor Destroy; override;
61 function Add(ItemClass: TBrushClass): TCustomBrush;
62 procedure Clear;
63 procedure Delete(Index: Integer);
64 function Insert(Index: Integer; ItemClass: TBrushClass): TCustomBrush;
65 property Owner: TPersistent read FOwner;
66 property Count: Integer read GetCount;
67 property Items[Index: Integer]: TCustomBrush read GetItem write SetItem; default;
68 end;
69
70 { TCustomBrush }
71 TCustomBrush = class(TNotifiablePersistent)
72 private
73 FBrushCollection: TBrushCollection;
74 FVisible: Boolean;
75 function GetIndex: Integer;
76 procedure SetBrushCollection(const Value: TBrushCollection);
77 procedure SetVisible(const Value: Boolean);
78 protected
79 procedure SetIndex(Value: Integer); virtual;
80 procedure UpdateRenderer(Renderer: TCustomPolygonRenderer); virtual;
81 public
82 constructor Create(ABrushCollection: TBrushCollection); virtual;
83 destructor Destroy; override;
84 procedure Changed; override;
85 procedure PolyPolygonFS(Renderer: TCustomPolygonRenderer;
86 const Points: TArrayOfArrayOfFloatPoint;
87 const ClipRect: TFloatRect; Transformation: TTransformation;
88 Closed: Boolean); virtual;
89 procedure PolygonFS(Renderer: TCustomPolygonRenderer;
90 const Points: TArrayOfFloatPoint;
91 const ClipRect: TFloatRect; Transformation: TTransformation;
92 Closed: Boolean); virtual;
93 property Index: Integer read GetIndex write SetIndex;
94 property BrushCollection: TBrushCollection read FBrushCollection write SetBrushCollection;
95 property Visible: Boolean read FVisible write SetVisible;
96 end;
97
98
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
117 { TNestedBrush }
118 TNestedBrush = class(TSolidBrush)
119 private
120 FBrushes: TBrushCollection;
121 public
122 constructor Create(ABrushCollection: TBrushCollection); override;
123 destructor Destroy; override;
124 procedure PolyPolygonFS(Renderer: TCustomPolygonRenderer;
125 const Points: TArrayOfArrayOfFloatPoint;
126 const ClipRect: TFloatRect; Transformation: TTransformation;
127 Closed: Boolean); override;
128 procedure PolygonFS(Renderer: TCustomPolygonRenderer;
129 const Points: TArrayOfFloatPoint;
130 const ClipRect: TFloatRect; Transformation: TTransformation;
131 Closed: Boolean); override;
132 property Brushes: TBrushCollection read FBrushes;
133 end;
134
135 { TStrokeBrush }
136 TStrokeBrush = class(TSolidBrush)
137 private
138 FStrokeWidth: TFloat;
139 FJoinStyle: TJoinStyle;
140 FMiterLimit: TFloat;
141 FEndStyle: TEndStyle;
142 procedure SetStrokeWidth(const Value: TFloat);
143 procedure SetEndStyle(const Value: TEndStyle);
144 procedure SetJoinStyle(const Value: TJoinStyle);
145 procedure SetMiterLimit(const Value: TFloat);
146 public
147 constructor Create(BrushCollection: TBrushCollection); override;
148 procedure PolyPolygonFS(Renderer: TCustomPolygonRenderer;
149 const Points: TArrayOfArrayOfFloatPoint;
150 const ClipRect: TFloatRect; Transformation: TTransformation;
151 Closed: Boolean); override;
152 property StrokeWidth: TFloat read FStrokeWidth write SetStrokeWidth;
153 property JoinStyle: TJoinStyle read FJoinStyle write SetJoinStyle;
154 property EndStyle: TEndStyle read FEndStyle write SetEndStyle;
155 property MiterLimit: TFloat read FMiterLimit write SetMiterLimit;
156 end;
157
158 { TGrowBrush }
159 TGrowBrush = class(TNestedBrush)
160 private
161 FGrowAmount: TFloat;
162 FJoinStyle: TJoinStyle;
163 FMiterLimit: TFloat;
164 procedure SetGrowAmount(const Value: TFloat);
165 procedure SetJoinStyle(const Value: TJoinStyle);
166 procedure SetMiterLimit(const Value: TFloat);
167 public
168 constructor Create(BrushCollection: TBrushCollection); override;
169 procedure PolyPolygonFS(Renderer: TCustomPolygonRenderer;
170 const Points: TArrayOfArrayOfFloatPoint;
171 const ClipRect: TFloatRect; Transformation: TTransformation;
172 Closed: Boolean); override;
173 property GrowAmount: TFloat read FGrowAmount write SetGrowAmount;
174 property JoinStyle: TJoinStyle read FJoinStyle write SetJoinStyle;
175 property MiterLimit: TFloat read FMiterLimit write SetMiterLimit;
176 end;
177
178 { TDashedBrush }
179 TDashedBrush = class(TStrokeBrush)
180 private
181 FDashOffset: TFloat;
182 FDashArray: TArrayOfFloat;
183 procedure SetDashOffset(const Value: TFloat);
184 public
185 procedure PolyPolygonFS(Renderer: TCustomPolygonRenderer;
186 const Points: TArrayOfArrayOfFloatPoint;
187 const ClipRect: TFloatRect; Transformation: TTransformation;
188 Closed: Boolean); override;
189 procedure SetDashArray(const ADashArray: array of TFloat);
190 property DashOffset: TFloat read FDashOffset write SetDashOffset;
191 end;
192
193implementation
194
195uses
196 GR32_VectorUtils;
197
198{ TBrushCollection }
199
200function TBrushCollection.Add(ItemClass: TBrushClass): TCustomBrush;
201begin
202 Result := ItemClass.Create(Self);
203 Result.Index := FItems.Count - 1;
204 //Notify(lnLayerAdded, Result, Result.Index);
205end;
206
207procedure TBrushCollection.Clear;
208begin
209 BeginUpdate;
210 try
211 while FItems.Count > 0 do TCustomBrush(FItems.Last).Free;
212 //Notify(lnCleared, nil, 0);
213 finally
214 EndUpdate;
215 end;
216end;
217
218constructor TBrushCollection.Create(AOwner: TPersistent);
219begin
220 FItems := TList.Create;
221end;
222
223procedure TBrushCollection.Delete(Index: Integer);
224begin
225 TCustomBrush(FItems[Index]).Free;
226end;
227
228destructor TBrushCollection.Destroy;
229begin
230 if Assigned(FItems) then Clear;
231 FItems.Free;
232 inherited;
233end;
234
235function TBrushCollection.GetCount: Integer;
236begin
237 Result := FItems.Count;
238end;
239
240function TBrushCollection.GetItem(Index: Integer): TCustomBrush;
241begin
242 Result := FItems[Index];
243end;
244
245function TBrushCollection.Insert(Index: Integer;
246 ItemClass: TBrushClass): TCustomBrush;
247begin
248 BeginUpdate;
249 try
250 Result := Add(ItemClass);
251 Result.Index := Index;
252 //Notify(lnLayerInserted, Result, Index);
253 finally
254 EndUpdate;
255 end;
256end;
257
258procedure TBrushCollection.InsertItem(Item: TCustomBrush);
259(*
260var
261 Index: Integer;
262*)
263begin
264 BeginUpdate;
265 try
266 {Index := } FItems.Add(Item);
267 Item.FBrushCollection := Self;
268 //Notify(lnLayerAdded, Item, Index);
269 finally
270 EndUpdate;
271 end;
272end;
273
274procedure TBrushCollection.RemoveItem(Item: TCustomBrush);
275var
276 Index: Integer;
277begin
278 BeginUpdate;
279 try
280 Index := FItems.IndexOf(Item);
281 if Index >= 0 then
282 begin
283 FItems.Delete(Index);
284 Item.FBrushCollection := nil;
285 //Notify(lnLayerDeleted, Item, Index);
286 end;
287 finally
288 EndUpdate;
289 end;
290end;
291
292procedure TBrushCollection.SetItem(Index: Integer; const Value: TCustomBrush);
293begin
294 TCollectionItem(FItems[Index]).Assign(Value);
295end;
296
297
298{ TCustomBrush }
299
300procedure TCustomBrush.Changed;
301begin
302 inherited;
303 if Assigned(FBrushCollection) then
304 FBrushCollection.Changed;
305end;
306
307constructor TCustomBrush.Create(ABrushCollection: TBrushCollection);
308begin
309 BrushCollection := ABrushCollection;
310 FVisible := True;
311end;
312
313destructor TCustomBrush.Destroy;
314begin
315 SetBrushCollection(nil);
316 inherited;
317end;
318
319function TCustomBrush.GetIndex: Integer;
320begin
321 if Assigned(FBrushCollection) then
322 Result := FBrushCollection.FItems.IndexOf(Self)
323 else
324 Result := -1;
325end;
326
327procedure TCustomBrush.PolygonFS(Renderer: TCustomPolygonRenderer;
328 const Points: TArrayOfFloatPoint;
329 const ClipRect: TFloatRect; Transformation: TTransformation; Closed: Boolean);
330begin
331 //PolyPolygonFS(Renderer, PolyPolygon(Points), ClipRect, Transformation, Closed);
332 //Renderer.PolygonFS(Points, ClipRect, Transformation);
333 PolyPolygonFS(Renderer, PolyPolygon(Points), ClipRect, Transformation, Closed);
334end;
335
336procedure TCustomBrush.PolyPolygonFS(Renderer: TCustomPolygonRenderer;
337 const Points: TArrayOfArrayOfFloatPoint;
338 const ClipRect: TFloatRect; Transformation: TTransformation; Closed: Boolean);
339begin
340 UpdateRenderer(Renderer);
341 Renderer.PolyPolygonFS(Points, ClipRect, Transformation);
342end;
343
344procedure TCustomBrush.SetBrushCollection(const Value: TBrushCollection);
345begin
346 if FBrushCollection <> Value then
347 begin
348 if Assigned(FBrushCollection) then
349 FBrushCollection.RemoveItem(Self);
350 if Assigned(Value) then
351 Value.InsertItem(Self);
352 end;
353end;
354
355procedure TCustomBrush.SetIndex(Value: Integer);
356var
357 CurIndex: Integer;
358begin
359 CurIndex := GetIndex;
360 if (CurIndex >= 0) and (CurIndex <> Value) then
361 with FBrushCollection do
362 begin
363 if Value < 0 then Value := 0;
364 if Value >= Count then Value := Count - 1;
365 if Value <> CurIndex then
366 begin
367 if Visible then BeginUpdate;
368 try
369 FBrushCollection.FItems.Move(CurIndex, Value);
370 finally
371 if Visible then EndUpdate;
372 end;
373 end;
374 end;
375end;
376
377procedure TCustomBrush.SetVisible(const Value: Boolean);
378begin
379 if FVisible <> Value then
380 begin
381 FVisible := Value;
382 Changed;
383 end;
384end;
385
386procedure TCustomBrush.UpdateRenderer(Renderer: TCustomPolygonRenderer);
387begin
388
389end;
390
391
392{ TNestedBrush }
393
394constructor TNestedBrush.Create(ABrushCollection: TBrushCollection);
395begin
396 inherited;
397 FBrushes := TBrushCollection.Create(Self);
398end;
399
400destructor TNestedBrush.Destroy;
401begin
402 FBrushes.Free;
403 inherited;
404end;
405
406procedure TNestedBrush.PolygonFS(Renderer: TCustomPolygonRenderer;
407 const Points: TArrayOfFloatPoint; const ClipRect: TFloatRect;
408 Transformation: TTransformation; Closed: Boolean);
409var
410 I: Integer;
411begin
412 for I := 0 to FBrushes.Count - 1 do
413 if FBrushes[I].Visible then
414 FBrushes[I].PolygonFS(Renderer, Points, ClipRect, Transformation, Closed);
415end;
416
417procedure TNestedBrush.PolyPolygonFS(Renderer: TCustomPolygonRenderer;
418 const Points: TArrayOfArrayOfFloatPoint; const ClipRect: TFloatRect;
419 Transformation: TTransformation; Closed: Boolean);
420var
421 I: Integer;
422begin
423 for I := 0 to FBrushes.Count - 1 do
424 if FBrushes[I].Visible then
425 FBrushes[I].PolyPolygonFS(Renderer, Points, ClipRect, Transformation, Closed);
426end;
427
428
429
430{ TSolidBrush }
431
432constructor TSolidBrush.Create(ABrushCollection: TBrushCollection);
433begin
434 inherited;
435 FFillColor := clBlack32;
436end;
437
438procedure TSolidBrush.SetFillColor(const Value: TColor32);
439begin
440 if FFillColor <> Value then
441 begin
442 FFillColor := Value;
443 Changed;
444 end;
445end;
446
447procedure TSolidBrush.SetFiller(const Value: TCustomPolygonFiller);
448begin
449 if FFiller <> Value then
450 begin
451 FFiller := Value;
452 Changed;
453 end;
454end;
455
456procedure TSolidBrush.SetFillMode(const Value: TPolyFillMode);
457begin
458 if FFillMode <> Value then
459 begin
460 FFillMode := Value;
461 Changed;
462 end;
463end;
464
465procedure TSolidBrush.UpdateRenderer(Renderer: TCustomPolygonRenderer);
466var
467 R: TPolygonRenderer32;
468begin
469 R := Renderer as TPolygonRenderer32;
470 R.Color := FillColor;
471 R.FillMode := FillMode;
472 R.Filler := Filler;
473end;
474
475
476{ TStrokeBrush }
477
478constructor TStrokeBrush.Create(BrushCollection: TBrushCollection);
479begin
480 inherited;
481 FStrokeWidth := 1;
482 FFillMode := pfWinding;
483 FMiterLimit := DEFAULT_MITER_LIMIT;
484end;
485
486procedure TStrokeBrush.PolyPolygonFS(Renderer: TCustomPolygonRenderer;
487 const Points: TArrayOfArrayOfFloatPoint; const ClipRect: TFloatRect;
488 Transformation: TTransformation; Closed: Boolean);
489var
490 APoints: TArrayOfArrayOfFloatPoint;
491begin
492 APoints := BuildPolyPolyLine(Points, Closed, StrokeWidth, JoinStyle,
493 EndStyle, MiterLimit);
494 inherited PolyPolygonFS(Renderer, APoints, ClipRect, Transformation, Closed);
495end;
496
497procedure TStrokeBrush.SetEndStyle(const Value: TEndStyle);
498begin
499 if FEndStyle <> Value then
500 begin
501 FEndStyle := Value;
502 Changed;
503 end;
504end;
505
506procedure TStrokeBrush.SetJoinStyle(const Value: TJoinStyle);
507begin
508 if FJoinStyle <> Value then
509 begin
510 FJoinStyle := Value;
511 Changed;
512 end;
513end;
514
515procedure TStrokeBrush.SetMiterLimit(const Value: TFloat);
516begin
517 if FMiterLimit <> Value then
518 begin
519 FMiterLimit := Value;
520 Changed;
521 end;
522end;
523
524procedure TStrokeBrush.SetStrokeWidth(const Value: TFloat);
525begin
526 if FStrokeWidth <> Value then
527 begin
528 FStrokeWidth := Value;
529 Changed;
530 end;
531end;
532
533
534{ TDashedBrush }
535
536procedure TDashedBrush.PolyPolygonFS(Renderer: TCustomPolygonRenderer;
537 const Points: TArrayOfArrayOfFloatPoint; const ClipRect: TFloatRect;
538 Transformation: TTransformation; Closed: Boolean);
539var
540 I: Integer;
541begin
542 for I := 0 to High(Points) do
543 inherited PolyPolygonFS(
544 Renderer, BuildDashedLine(Points[I], FDashArray, FDashOffset, Closed),
545 ClipRect, Transformation, False);
546end;
547
548procedure TDashedBrush.SetDashArray(const ADashArray: array of TFloat);
549var
550 L: Integer;
551begin
552 L := Length(ADashArray);
553 SetLength(FDashArray, L);
554 Move(ADashArray[0], FDashArray[0], L * SizeOf(TFloat));
555 Changed;
556end;
557
558procedure TDashedBrush.SetDashOffset(const Value: TFloat);
559begin
560 if FDashOffset <> Value then
561 begin
562 FDashOffset := Value;
563 Changed;
564 end;
565end;
566
567
568{ TGrowBrush }
569
570constructor TGrowBrush.Create(BrushCollection: TBrushCollection);
571begin
572 inherited;
573 FMiterLimit := DEFAULT_MITER_LIMIT;
574end;
575
576procedure TGrowBrush.PolyPolygonFS(Renderer: TCustomPolygonRenderer;
577 const Points: TArrayOfArrayOfFloatPoint; const ClipRect: TFloatRect;
578 Transformation: TTransformation; Closed: Boolean);
579var
580 I: Integer;
581 APoints: TArrayOfArrayOfFloatPoint;
582begin
583 SetLength(APoints, Length(Points));
584 for I := 0 to High(Points) do
585 APoints[I] := Grow(Points[I], GrowAmount, JoinStyle, Closed, MiterLimit);
586 inherited PolyPolygonFS(Renderer, APoints, ClipRect, Transformation, True);
587end;
588
589procedure TGrowBrush.SetGrowAmount(const Value: TFloat);
590begin
591 if FGrowAmount <> Value then
592 begin
593 FGrowAmount := Value;
594 Changed;
595 end;
596end;
597
598procedure TGrowBrush.SetJoinStyle(const Value: TJoinStyle);
599begin
600 if FJoinStyle <> Value then
601 begin
602 FJoinStyle := Value;
603 Changed;
604 end;
605end;
606
607procedure TGrowBrush.SetMiterLimit(const Value: TFloat);
608begin
609 if FMiterLimit <> Value then
610 begin
611 FMiterLimit := Value;
612 Changed;
613 end;
614end;
615
616end.
Note: See TracBrowser for help on using the repository browser.