source: trunk/Packages/bgrabitmap/bgracanvas.pas

Last change on this file was 2, checked in by chronos, 5 years ago
File size: 44.4 KB
Line 
1unit BGRACanvas;
2
3{$mode objfpc}{$H+}
4
5interface
6
7uses
8 Classes, SysUtils, FPCanvas, BGRAGraphics, Types, FPImage, BGRABitmapTypes;
9
10type
11
12 { TBGRAColoredObject }
13
14 TBGRAColoredObject = class
15 private
16 function GetColor: TColor;
17 function GetOpacity: Byte;
18 procedure SetColor(const AValue: TColor);
19 procedure SetOpacity(const AValue: Byte);
20 public
21 BGRAColor: TBGRAPixel;
22 procedure Assign(Source: TObject); virtual;
23 property Color: TColor read GetColor write SetColor;
24 property Opacity: Byte read GetOpacity write SetOpacity;
25 end;
26
27 { TBGRAPen }
28
29 TBGRAPen = class(TBGRAColoredObject)
30 private
31 function GetActualColor: TBGRAPixel;
32 function GetActualWidth: integer;
33 function GetCustomPenStyle: TBGRAPenStyle;
34 function GetPenStyle: TPenStyle;
35 procedure SetCustomPenStyle(const AValue: TBGRAPenStyle);
36 procedure SetPenStyle(const AValue: TPenStyle);
37 protected
38 FCustomPenStyle: TBGRAPenStyle;
39 FPenStyle: TPenStyle;
40 public
41 Width: Integer;
42 EndCap: TPenEndCap;
43 JoinStyle: TPenJoinStyle;
44 constructor Create;
45 procedure Assign(Source: TObject); override;
46 property Style: TPenStyle read GetPenStyle Write SetPenStyle;
47 property CustomStyle: TBGRAPenStyle read GetCustomPenStyle write SetCustomPenStyle;
48 property ActualWidth: integer read GetActualWidth;
49 property ActualColor: TBGRAPixel read GetActualColor;
50 end;
51
52 { TBGRABrush }
53
54 TBGRABrush = class(TBGRAColoredObject)
55 private
56 function GetActualColor: TBGRAPixel;
57 function GetInvisible: boolean;
58 procedure SetBackColor(const AValue: TBGRAPixel);
59 procedure SetBrushStyle(const AValue: TBrushStyle);
60 protected
61 FStyle: TBrushStyle;
62 FBackColor: TBGRAPixel;
63 InternalBitmap: TBGRACustomBitmap;
64 InternalBitmapColor: TBGRAPixel;
65 public
66 Texture: IBGRAScanner;
67 constructor Create;
68 destructor Destroy; override;
69 procedure Assign(Source: TObject); override;
70 function BuildTexture(Prototype: TBGRACustomBitmap): IBGRAScanner;
71 property Style: TBrushStyle read FStyle write SetBrushStyle;
72 property BackColor: TBGRAPixel read FBackColor write SetBackColor;
73 property ActualColor: TBGRAPixel read GetActualColor;
74 property Invisible: boolean read GetInvisible;
75 end;
76
77 { TBGRAFont }
78
79 TBGRAFont = class(TBGRAColoredObject)
80 private
81 function GetAntialiasing: Boolean;
82 procedure SetAntialiasing(const AValue: Boolean);
83 public
84 Name: string;
85 Height: Integer;
86 Style: TFontStyles;
87 Quality : TBGRAFontQuality;
88 Orientation: integer;
89 Texture: IBGRAScanner;
90 constructor Create;
91 procedure Assign(Source: TObject); override;
92 property Antialiasing: Boolean read GetAntialiasing write SetAntialiasing;
93
94 end;
95
96 { TBGRACanvas }
97
98 TBGRACanvas = class
99 procedure SetBrush(const AValue: TBGRABrush);
100 procedure SetPen(const AValue: TBGRAPen);
101 function GetPixelColor(X, Y: Integer): TColor;
102 procedure SetPixelColor(X, Y: Integer; const AValue: TColor);
103 private
104 function GetClipping: Boolean;
105 function GetClipRect: TRect;
106 function GetExpandedPixel(X, Y: Integer): TExpandedPixel;
107 function GetFPPixelColor(X, Y: Integer): TFPColor;
108 function GetHeight: integer;
109 function GetWidth: integer;
110 procedure SetClipping(const AValue: Boolean);
111 procedure SetClipRect(const AValue: TRect);
112 procedure SetExpandedPixel(X, Y: Integer; const AValue: TExpandedPixel);
113 procedure SetFont(const AValue: TBGRAFont);
114 procedure SetFPPixelColor(X, Y: Integer; const AValue: TFPColor);
115 function ComputeEllipseC(x1, y1, x2, y2: integer; out cx,cy,rx,ry: single): boolean;
116 function CheckRectangle(var x1, y1, x2, y2: integer; out tx,ty: integer): boolean;
117
118 protected
119 FBitmap: TBGRACustomBitmap;
120 FBrush: TBGRABrush;
121 FPen: TBGRAPen;
122 FPenPos: TPoint;
123 FFont : TBGRAFont;
124 FInactiveClipRect: TRect;
125 FClippingOn: Boolean;
126 procedure ApplyPenStyle;
127 procedure ApplyFont;
128 function NoPen: boolean;
129 function NoBrush: boolean;
130 public
131 AntialiasingMode: TAntialiasingMode;
132 FillMode : TFillMode;
133 TextStyle : TTextStyle;
134 DrawFontBackground : boolean;
135 constructor Create(ABitmap: TBGRACustomBitmap);
136 destructor Destroy; override;
137 procedure MoveTo(x,y: integer);
138 procedure MoveTo(p: TPoint);
139 procedure LineTo(x,y: integer);
140 procedure LineTo(p: TPoint);
141 procedure Arc(x1,y1,x2,y2,sx,sy,ex,ey: integer);
142 procedure Arc(x1,y1,x2,y2,StartDeg16,LengthDeg16: integer);
143 procedure Arc65536(x1,y1,x2,y2: integer; start65536,end65536: word; Options: TArcOptions);
144 procedure Chord(x1,y1,x2,y2,sx,sy,ex,ey: integer);
145 procedure Chord(x1,y1,x2,y2,StartDeg16,LengthDeg16: integer);
146 procedure Pie(x1,y1,x2,y2,sx,sy,ex,ey: integer);
147 procedure Pie(x1,y1,x2,y2,StartDeg16,LengthDeg16: integer);
148 procedure RadialPie(x1,y1,x2,y2,StartDeg16,LengthDeg16: integer);
149 procedure Ellipse(x1,y1,x2,y2: integer);
150 procedure Ellipse(const bounds: TRect);
151 procedure Rectangle(x1,y1,x2,y2: integer; Filled: Boolean = True);
152 procedure Rectangle(const bounds: TRect; Filled: Boolean = True);
153 procedure Frame(x1,y1,x2,y2: integer);
154 procedure Frame(const bounds: TRect);
155 procedure RoundRect(x1,y1,x2,y2: integer; dx,dy: integer);
156 procedure RoundRect(const bounds: TRect; dx,dy: integer);
157 procedure EllipseC(x,y,rx,ry: integer);
158 procedure FillRect(x1,y1,x2,y2: integer);
159 procedure FillRect(const bounds: TRect);
160 procedure FrameRect(x1,y1,x2,y2: integer; width: integer = 1);
161 procedure FrameRect(const bounds: TRect; width: integer = 1);
162 procedure Frame3D(var bounds: TRect; width: integer; Style: TGraphicsBevelCut); overload;
163 procedure Frame3D(var bounds: TRect; width: integer; Style: TGraphicsBevelCut; LightColor: TBGRAPixel; ShadowColor: TBGRAPixel); overload;
164 procedure GradientFill(ARect: TRect; AStart, AStop: TColor;
165 ADirection: TGradientDirection; GammaCorrection: Boolean = false);
166 procedure FloodFill(X, Y: Integer; FillColor: TColor; FillStyle: TFillStyle);
167 procedure FloodFill(X, Y: Integer; FillColor: TBGRAPixel; FillStyle: TFillStyle);
168 procedure FloodFill(X, Y: Integer);
169 procedure Polygon(const APoints: array of TPoint);
170 procedure Polygon(const Points: array of TPoint;
171 Winding: Boolean;
172 StartIndex: Integer = 0;
173 NumPts: Integer = -1);
174 procedure Polygon(Points: PPoint; NumPts: Integer;
175 Winding: boolean = False);
176 procedure PolygonF(const APoints: array of TPointF);
177 procedure PolygonF(const APoints: array of TPointF; Winding: Boolean; FillOnly: Boolean = False);
178 procedure Polyline(const APoints: array of TPoint);
179 procedure Polyline(const Points: array of TPoint;
180 StartIndex: Integer;
181 NumPts: Integer = -1);
182 procedure Polyline(Points: PPoint; NumPts: Integer);
183 procedure PolylineF(const APoints: array of TPointF);
184 procedure PolyBezier(Points: PPoint; NumPts: Integer;
185 Filled: boolean = False;
186 Continuous: boolean = False);
187 procedure PolyBezier(const Points: array of TPoint;
188 Filled: boolean = False;
189 Continuous: boolean = False);
190 procedure Draw(X,Y: Integer; SrcBitmap: TBGRACustomBitmap); overload;
191 procedure Draw(X,Y: Integer; SrcBitmap: TBitmap); overload;
192 procedure CopyRect(X,Y: Integer; SrcBitmap: TBGRACustomBitmap; SrcRect: TRect);
193 procedure StretchDraw(DestRect: TRect; SrcBitmap: TBGRACustomBitmap; HorizFlip: Boolean = false; VertFlip: Boolean = false);
194 procedure DrawFocusRect(bounds: TRect);
195 procedure CopyRect(Dest: TRect; SrcBmp: TBGRACustomBitmap;
196 Source: TRect); virtual;
197
198 procedure TextOut(X,Y: Integer; const Text: String);
199 procedure TextRect(const ARect: TRect; X, Y: integer; const Text: string);
200 procedure TextRect(ARect: TRect; X, Y: integer; const Text: string;
201 const Style: TTextStyle);
202 function TextExtent(const Text: string): TSize;
203 function TextHeight(const Text: string): Integer;
204 function TextWidth(const Text: string): Integer;
205
206 property Pen: TBGRAPen read FPen write SetPen;
207 property PenPos : TPoint read FPenPos write FPenPos;
208 property Brush: TBGRABrush read FBrush write SetBrush;
209 property Font: TBGRAFont read FFont write SetFont;
210 property Pixels[X,Y: Integer]: TColor read GetPixelColor write SetPixelColor;
211 property GammaExpandedPixels[X,Y: Integer]: TExpandedPixel read GetExpandedPixel write SetExpandedPixel;
212 property Colors[X,Y: Integer]: TFPColor read GetFPPixelColor write SetFPPixelColor;
213 property Height: integer read GetHeight;
214 property Width : integer read GetWidth;
215 property ClipRect: TRect read GetClipRect write SetClipRect;
216 property Clipping: Boolean read GetClipping write SetClipping;
217 end;
218
219implementation
220
221uses BGRAPen, BGRAPath, BGRAPolygon, BGRAPolygonAliased, Math;
222
223{ TBGRAFont }
224
225function TBGRAFont.GetAntialiasing: Boolean;
226begin
227 result := Quality <> fqSystem;
228end;
229
230procedure TBGRAFont.SetAntialiasing(const AValue: Boolean);
231begin
232 if AValue = Antialiasing then exit;
233 if AValue then
234 Quality := fqFineAntialiasing
235 else
236 Quality := fqSystem;
237end;
238
239constructor TBGRAFont.Create;
240begin
241 Name := 'default';
242 Height := 12;
243 Style := [];
244 Antialiasing := False;
245 Orientation := 0;
246 Texture := nil;
247 BGRAColor := BGRABlack;
248end;
249
250procedure TBGRAFont.Assign(Source: TObject);
251var sf: TBGRAFont;
252 f: TFont;
253 cf: TFPCustomFont;
254begin
255 if Source is TFont then
256 begin
257 f := TFont(Source);
258 Color := f.Color;
259 Opacity := 255;
260 Style := f.Style;
261 Name := f.Name;
262 Orientation := f.Orientation;
263 if f.Height= 0 then
264 Height := 16 else
265 Height := f.Height;
266 end else
267 if Source is TBGRAFont then
268 begin
269 sf := Source as TBGRAFont;
270 Name := sf.Name;
271 Height := sf.Height;
272 Style := sf.Style;
273 Quality := sf.Quality;
274 Orientation := sf.Orientation;
275 Texture := sf.Texture;
276 end else
277 if Source is TFPCustomFont then
278 begin
279 cf := Source as TFPCustomFont;
280 Color := FPColorToTColor(cf.FPColor);
281 Style := [];
282 if cf.Bold then Style += [fsBold];
283 if cf.Italic then Style += [fsItalic];
284 if cf.Underline then Style += [fsUnderline];
285{$IF FPC_FULLVERSION>=20602} //changed in 2.6.2 and 2.7
286 if cf.StrikeThrough then Style += [fsStrikeOut];
287{$ELSE}
288 if cf.StrikeTrough then Style += [fsStrikeOut];
289{$ENDIF}
290 Name := cf.Name;
291 //Orientation := cf.Orientation;
292 if cf.Size = 0 then
293 Height := 16 else
294 Height := round(cf.Size*1.8);
295 end;
296 inherited Assign(Source);
297end;
298
299{ TBGRABrush }
300
301function TBGRABrush.GetActualColor: TBGRAPixel;
302begin
303 if (Style = bsClear) or (Opacity = 0) then
304 result := BGRAPixelTransparent
305 else
306 result := BGRAColor;
307end;
308
309function TBGRABrush.GetInvisible: boolean;
310begin
311 result := (texture = nil) and ((style = bsClear) or ((style= bsSolid) and (bgracolor.alpha = 0))
312 or ((bgracolor.alpha = 0) and (BackColor.alpha = 0)));
313end;
314
315procedure TBGRABrush.SetBackColor(const AValue: TBGRAPixel);
316begin
317 if FBackColor=AValue then exit;
318 FBackColor:=AValue;
319 FreeAndNil(InternalBitmap);
320end;
321
322procedure TBGRABrush.SetBrushStyle(const AValue: TBrushStyle);
323begin
324 if FStyle=AValue then exit;
325 FStyle:=AValue;
326 FreeAndNil(InternalBitmap);
327end;
328
329constructor TBGRABrush.Create;
330begin
331 BGRAColor := BGRAWhite;
332 InternalBitmap := nil;
333 InternalBitmapColor := BGRAPixelTransparent;
334 Style := bsSolid;
335 Texture := nil;
336 BackColor := BGRAPixelTransparent;
337end;
338
339destructor TBGRABrush.Destroy;
340begin
341 Texture := nil;
342 InternalBitmap.Free;
343 inherited Destroy;
344end;
345
346procedure TBGRABrush.Assign(Source: TObject);
347var sb: TBGRABrush;
348 b: TBrush;
349begin
350 if Source is TBGRABrush then
351 begin
352 sb := Source as TBGRABrush;
353 Texture := sb.Texture;
354 BackColor := sb.BackColor;
355 Style := sb.Style;
356 end else
357 if Source is TBrush then
358 begin
359 b := Source as TBrush;
360 Color := b.Color;
361 Opacity := 255;
362 Style := b.Style;
363 end;
364 inherited Assign(Source);
365end;
366
367function TBGRABrush.BuildTexture(Prototype: TBGRACustomBitmap): IBGRAScanner;
368begin
369 //user-defined texture
370 if Texture <> nil then
371 result := texture
372 else
373 begin
374 //free pattern if color has changed
375 if (InternalBitmap <> nil) and (InternalBitmapColor <> BGRAColor) then
376 FreeAndNil(InternalBitmap);
377
378 //styles that do not have pattern
379 if Style in[bsSolid,bsClear] then
380 result := nil
381 else
382 begin
383 //create pattern if needed
384 if InternalBitmap = nil then
385 begin
386 InternalBitmap := CreateBrushTexture(Prototype, Style, BGRAColor,BackColor);
387 InternalBitmapColor := BGRAColor;
388 end;
389 result := InternalBitmap;
390 end;
391 end;
392end;
393
394{ TBGRAPen }
395
396function TBGRAPen.GetActualColor: TBGRAPixel;
397begin
398 if (Style = psClear) or (Opacity = 0) then
399 result := BGRAPixelTransparent
400 else
401 result := BGRAColor;
402end;
403
404function TBGRAPen.GetActualWidth: integer;
405begin
406 if width < 1 then result := 1 else
407 result := Width;
408end;
409
410function TBGRAPen.GetCustomPenStyle: TBGRAPenStyle;
411begin
412 result := DuplicatePenStyle(FCustomPenStyle);
413end;
414
415function TBGRAPen.GetPenStyle: TPenStyle;
416begin
417 Result:= FPenStyle;
418end;
419
420procedure TBGRAPen.SetCustomPenStyle(const AValue: TBGRAPenStyle);
421begin
422 FCustomPenStyle := DuplicatePenStyle(AValue);
423 FPenStyle:= BGRAToPenStyle(AValue);
424end;
425
426procedure TBGRAPen.SetPenStyle(const AValue: TPenStyle);
427begin
428 if AValue = psPattern then exit;
429 Case AValue of
430 psSolid: FCustomPenStyle := SolidPenStyle;
431 psDash: FCustomPenStyle := DashPenStyle;
432 psDot: FCustomPenStyle := DotPenStyle;
433 psDashDot: FCustomPenStyle := DashDotPenStyle;
434 psDashDotDot: FCustomPenStyle := DashDotDotPenStyle;
435 else FCustomPenStyle := ClearPenStyle;
436 end;
437 FPenStyle := AValue;
438end;
439
440constructor TBGRAPen.Create;
441begin
442 Width := 1;
443 EndCap := pecRound;
444 JoinStyle := pjsRound;
445 Style := psSolid;
446 BGRAColor := BGRABlack;
447end;
448
449procedure TBGRAPen.Assign(Source: TObject);
450var sp: TBGRAPen;
451 p: TPen;
452begin
453 if Source is TBGRAPen then
454 begin
455 sp := Source as TBGRAPen;
456 Width := sp.Width;
457 EndCap := sp.EndCap;
458 JoinStyle := sp.JoinStyle;
459 Style := sp.Style;
460 CustomStyle := sp.CustomStyle;
461 end else
462 if Source is TPen then
463 begin
464 p := Source as TPen;
465 Width := p.Width;
466 EndCap := p.EndCap;
467 JoinStyle := p.JoinStyle;
468 Style := p.Style;
469 Color := p.Color;
470 Opacity := 255;
471 end;
472 inherited Assign(Source);
473end;
474
475{ TBGRAColoredObject }
476
477function TBGRAColoredObject.GetColor: TColor;
478begin
479 result := BGRAToColor(BGRAColor);
480end;
481
482function TBGRAColoredObject.GetOpacity: Byte;
483begin
484 result := BGRAColor.alpha;
485end;
486
487procedure TBGRAColoredObject.SetColor(const AValue: TColor);
488begin
489 BGRAColor := ColorToBGRA(ColorToRGB(AValue),BGRAColor.alpha);
490end;
491
492procedure TBGRAColoredObject.SetOpacity(const AValue: Byte);
493begin
494 BGRAColor.alpha := AValue;
495end;
496
497procedure TBGRAColoredObject.Assign(Source: TObject);
498var so: TBGRAColoredObject;
499begin
500 if Source is TBGRAColoredObject then
501 begin
502 so := Source as TBGRAColoredObject;
503 BGRAColor := so.BGRAColor;
504 end;
505end;
506
507{ TBGRACanvas }
508
509procedure TBGRACanvas.SetBrush(const AValue: TBGRABrush);
510begin
511 if FBrush=AValue then exit;
512 FBrush.Assign(AValue);
513end;
514
515procedure TBGRACanvas.SetPen(const AValue: TBGRAPen);
516begin
517 if FPen=AValue then exit;
518 FPen.Assign(AValue);
519end;
520
521function TBGRACanvas.GetPixelColor(X, Y: Integer): TColor;
522begin
523 result := BGRAToColor(FBitmap.GetPixel(x,y));
524end;
525
526procedure TBGRACanvas.SetPixelColor(X, Y: Integer; const AValue: TColor);
527begin
528 FBitmap.SetPixel(x,y,ColorToBGRA(AValue));
529end;
530
531function TBGRACanvas.GetClipping: Boolean;
532begin
533 result := FClippingOn;
534end;
535
536function TBGRACanvas.GetClipRect: TRect;
537begin
538 if not Clipping then
539 result := FInactiveClipRect else
540 result := FBitmap.ClipRect;
541end;
542
543function TBGRACanvas.GetExpandedPixel(X, Y: Integer): TExpandedPixel;
544begin
545 result := GammaExpansion(FBitmap.GetPixel(X,Y));
546end;
547
548function TBGRACanvas.GetFPPixelColor(X, Y: Integer): TFPColor;
549begin
550 result := BGRAToFPColor(FBitmap.GetPixel(x,y));
551end;
552
553function TBGRACanvas.GetHeight: integer;
554begin
555 result := FBitmap.Height;
556end;
557
558function TBGRACanvas.GetWidth: integer;
559begin
560 result := FBitmap.Width;
561end;
562
563procedure TBGRACanvas.SetClipping(const AValue: Boolean);
564begin
565 FClippingOn := AValue;
566 if not AValue then FBitmap.NoClip else
567 FBitmap.ClipRect := FInactiveClipRect;
568end;
569
570procedure TBGRACanvas.SetClipRect(const AValue: TRect);
571begin
572 FInactiveClipRect := AValue;
573 if FClippingOn then
574 begin
575 FBitmap.ClipRect := AValue;
576 FInactiveClipRect := FBitmap.ClipRect;
577 end;
578end;
579
580procedure TBGRACanvas.SetExpandedPixel(X, Y: Integer;
581 const AValue: TExpandedPixel);
582begin
583 FBitmap.SetPixel(x,y,GammaCompression(AValue));
584end;
585
586procedure TBGRACanvas.SetFont(const AValue: TBGRAFont);
587begin
588 if FFont=AValue then exit;
589 FFont.Assign(AValue);
590end;
591
592procedure TBGRACanvas.SetFPPixelColor(X, Y: Integer; const AValue: TFPColor);
593begin
594 FBitmap.SetPixel(x,y,FPColorToBGRA(AValue));
595end;
596
597function TBGRACanvas.ComputeEllipseC(x1, y1, x2, y2: integer; out cx, cy, rx,
598 ry: single): boolean;
599begin
600 cx := (x1+x2-1)/2;
601 cy := (y1+y2-1)/2;
602 rx := abs((x2-x1)/2);
603 ry := abs((y2-y1)/2);
604 result := (rx<>0) and (ry<>0);
605end;
606
607function TBGRACanvas.CheckRectangle(var x1, y1, x2, y2: integer; out tx, ty: integer
608 ): boolean;
609var
610 temp: integer;
611begin
612 if x1 > x2 then
613 begin
614 temp := x1;
615 x1 := x2;
616 x2 := temp;
617 end;
618 if y1 > y2 then
619 begin
620 temp := y1;
621 y1 := y2;
622 y2 := temp;
623 end;
624 tx := x2-x1;
625 ty := y2-y1;
626 result := (tx<>0) and (ty <>0);
627end;
628
629procedure TBGRACanvas.ApplyPenStyle;
630var
631 TempPenStyle: TBGRAPenStyle;
632 i: Integer;
633begin
634 FBitmap.JoinStyle := FPen.JoinStyle;
635 FBitmap.LineCap := FPen.EndCap;
636 if FPen.Width = 1 then
637 begin
638 SetLength(TempPenStyle, length(FPen.CustomStyle));
639 for i := 0 to high(TempPenStyle) do
640 TempPenStyle[i] := FPen.CustomStyle[i]*4;
641 FBitmap.CustomPenStyle := TempPenStyle;
642 end else
643 FBitmap.CustomPenStyle := FPen.CustomStyle;
644end;
645
646procedure TBGRACanvas.ApplyFont;
647begin
648 FBitmap.FontName := Font.Name;
649 FBitmap.FontHeight := -Font.Height;
650 FBitmap.FontStyle := Font.Style;
651 FBitmap.FontQuality := Font.Quality;
652 FBitmap.FontOrientation := Font.Orientation;
653end;
654
655function TBGRACanvas.NoPen: boolean;
656begin
657 result := Pen.ActualColor.alpha = 0;
658end;
659
660function TBGRACanvas.NoBrush: boolean;
661begin
662 result := Brush.Invisible;
663end;
664
665constructor TBGRACanvas.Create(ABitmap: TBGRACustomBitmap);
666begin
667 FBitmap := ABitmap;
668 AntialiasingMode := amOn;
669 FPen := TBGRAPen.Create;
670 FPenPos := Point(0,0);
671 FFont := TBGRAFont.Create;
672 FBrush := TBGRABrush.Create;
673 FClippingOn := False;
674 FInactiveClipRect := FBitmap.ClipRect;
675 FillMode := fmWinding;
676 DrawFontBackground := True;
677end;
678
679destructor TBGRACanvas.Destroy;
680begin
681 FPen.Free;
682 FBrush.Free;
683 FFont.Free;
684end;
685
686procedure TBGRACanvas.MoveTo(x, y: integer);
687begin
688 MoveTo(Point(x,y));
689end;
690
691procedure TBGRACanvas.MoveTo(p: TPoint);
692begin
693 FPenPos := p;
694end;
695
696procedure TBGRACanvas.LineTo(x, y: integer);
697var pts: array of TPointF;
698begin
699 if not NoPen then
700 begin
701 //1 pixel-wide solid pen is rendered with pixel line
702 if (Pen.Style = psSolid) and (Pen.ActualWidth = 1) then
703 begin
704 if AntialiasingMode = amOff then
705 FBitmap.DrawLine(FPenPos.x,FPenPos.y,x,y,Pen.ActualColor,False)
706 else
707 FBitmap.DrawLineAntialias(FPenPos.x,FPenPos.y,x,y,Pen.ActualColor,False);
708 end else
709 begin
710 ApplyPenStyle;
711 if AntialiasingMode = amOff then
712 begin
713 pts := FBitmap.ComputeWidePolyline([PointF(FPenPos.x,FPenPos.y),PointF(x,y)],Pen.ActualWidth);
714 FBitmap.FillPoly(pts,Pen.ActualColor,dmDrawWithTransparency);
715 end else
716 FBitmap.DrawLineAntialias(FPenPos.x,FPenPos.y,x,y,Pen.ActualColor,Pen.ActualWidth);
717 end;
718 end;
719 MoveTo(x,y);
720end;
721
722procedure TBGRACanvas.LineTo(p: TPoint);
723begin
724 LineTo(p.x,p.y);
725end;
726
727procedure TBGRACanvas.Arc(x1, y1, x2, y2, sx, sy, ex, ey: integer);
728var
729 angle1,angle2: word;
730 cx,cy,rx,ry: single;
731begin
732 if not ComputeEllipseC(x1,y1,x2,y2,cx,cy,rx,ry) then exit;
733 angle1 := round(arctan2(-(sy-cy)/ry,(sx-cx)/rx)*65536/(2*Pi));
734 angle2 := round(arctan2(-(ey-cy)/ry,(ex-cx)/rx)*65536/(2*Pi));
735 Arc65536(x1,y1,x2,y2,angle1, angle2, []);
736end;
737
738procedure TBGRACanvas.Arc(x1, y1, x2, y2, StartDeg16, LengthDeg16: integer);
739begin
740 if LengthDeg16 > 360*16 then LengthDeg16 := 360*16;
741 Arc65536(x1,y1,x2,y2,StartDeg16*512 div 45, (StartDeg16+LengthDeg16)*512 div 45, []);
742end;
743
744procedure TBGRACanvas.Arc65536(x1, y1, x2, y2: integer; start65536, end65536: word; Options: TArcOptions);
745var cx,cy,rx,ry,w: single;
746 arcPts,penPts: array of TPointF;
747 multi: TBGRAMultishapeFiller;
748 tex: IBGRAScanner;
749begin
750 if NoPen and NoBrush then exit;
751 if not ComputeEllipseC(x1,y1,x2,y2,cx,cy,rx,ry) then exit;
752
753 rx -=0.50;
754 ry -=0.50;
755 w := Pen.ActualWidth;
756
757 if AntialiasingMode = amOff then
758 begin
759 if not NoPen and not Odd(Pen.ActualWidth) then
760 begin
761 rx -= 0.01;
762 ry -= 0.01;
763 end;
764 end;
765
766 if NoPen then
767 begin
768 cx -=0.5;
769 cy -=0.5;
770 rx -=0.2;
771 ry -=0.2;
772 if (rx<0) or (ry<0) then exit;
773 end;
774
775 multi := TBGRAMultishapeFiller.Create;
776 multi.Antialiasing := AntialiasingMode <> amOff;
777 multi.FillMode := FillMode;
778 multi.PolygonOrder := poLastOnTop;
779 multi.AliasingIncludeBottomRight := True;
780 arcPts := ComputeArc65536(cx,cy,rx,ry,start65536,end65536);
781 if (aoPie in Options) and (start65536 <> end65536) then
782 begin
783 setlength(arcPts,length(arcPts)+1);
784 arcPts[high(arcPts)] := PointF(cx,cy);
785 end;
786 if (aoFillPath in Options) and not NoBrush then
787 begin
788 tex := Brush.BuildTexture(FBitmap);
789 if tex <> nil then
790 multi.AddPolygon(arcPts,tex) else
791 multi.AddPolygon(arcPts,Brush.ActualColor);
792 end;
793 if not NoPen then
794 begin
795 ApplyPenStyle;
796 if (aoClosePath in Options) or (aoPie in Options) then
797 penPts := FBitmap.ComputeWidePolygon(arcPts,w)
798 else
799 penPts := FBitmap.ComputeWidePolyline(arcPts,w);
800 multi.AddPolygon( penPts, Pen.ActualColor );
801 end;
802 multi.Draw(FBitmap);
803 multi.Free;
804end;
805
806procedure TBGRACanvas.Chord(x1, y1, x2, y2, sx, sy, ex, ey: integer);
807var
808 angle1,angle2: word;
809 cx,cy,rx,ry: single;
810begin
811 if not ComputeEllipseC(x1,y1,x2,y2,cx,cy,rx,ry) then exit;
812 angle1 := round(arctan2(-(sy-cy)/ry,(sx-cx)/rx)*65536/(2*Pi)) and 65535;
813 angle2 := round(arctan2(-(ey-cy)/ry,(ex-cx)/rx)*65536/(2*Pi)) and 65535;
814 Arc65536(x1,y1,x2,y2,angle1, angle2, [aoClosePath,aoFillPath]);
815end;
816
817procedure TBGRACanvas.Chord(x1, y1, x2, y2, StartDeg16, LengthDeg16: integer);
818begin
819 if LengthDeg16 > 360*16 then LengthDeg16 := 360*16;
820 Arc65536(x1,y1,x2,y2,StartDeg16*512 div 45, (StartDeg16+LengthDeg16)*512 div 45,[aoClosePath,aoFillPath]);
821end;
822
823procedure TBGRACanvas.Pie(x1, y1, x2, y2, sx, sy, ex, ey: integer);
824var
825 angle1,angle2: word;
826 cx,cy,rx,ry: single;
827begin
828 if not ComputeEllipseC(x1,y1,x2,y2,cx,cy,rx,ry) then exit;
829 angle1 := round(arctan2(-(sy-cy)/ry,(sx-cx)/rx)*65536/(2*Pi)) and 65535;
830 angle2 := round(arctan2(-(ey-cy)/ry,(ex-cx)/rx)*65536/(2*Pi)) and 65535;
831 Arc65536(x1,y1,x2,y2,angle1, angle2, [aoPie,aoFillPath]);
832end;
833
834procedure TBGRACanvas.Pie(x1, y1, x2, y2, StartDeg16, LengthDeg16: integer);
835begin
836 if LengthDeg16 > 360*16 then LengthDeg16 := 360*16;
837 Arc65536(x1,y1,x2,y2,StartDeg16*512 div 45, (StartDeg16+LengthDeg16)*512 div 45,[aoPie,aoFillPath]);
838end;
839
840procedure TBGRACanvas.RadialPie(x1, y1, x2, y2, StartDeg16, LengthDeg16: integer
841 );
842begin
843 Pie(x1,y1,x2,y2,StartDeg16,LengthDeg16);
844end;
845
846procedure TBGRACanvas.Ellipse(x1, y1, x2, y2: integer);
847var cx,cy,rx,ry,w: single;
848 tex: IBGRAScanner;
849 multi: TBGRAMultishapeFiller;
850begin
851 if NoPen and NoBrush then exit;
852 tex := Brush.BuildTexture(FBitmap);
853 if (AntialiasingMode = amOff) and not NoPen and (Pen.Style = psSolid) and (Pen.ActualWidth = 1) then
854 begin
855 BGRARoundRectAliased(FBitmap,x1,y1,x2,y2,abs(x2-x1),abs(y2-y1),Pen.ActualColor,Brush.ActualColor,tex);
856 exit;
857 end;
858 if not ComputeEllipseC(x1,y1,x2,y2,cx,cy,rx,ry) then exit;
859 tex := Brush.BuildTexture(FBitmap);
860 w := Pen.ActualWidth;
861 rx -=0.50;
862 ry -=0.50;
863
864 if AntialiasingMode = amOff then
865 begin
866 if not NoPen and not Odd(Pen.ActualWidth) then
867 begin
868 rx -= 0.01;
869 ry -= 0.01;
870 end;
871 end;
872
873 if NoPen then
874 begin
875 cx -=0.5;
876 cy -=0.5;
877 rx -=0.2;
878 ry -=0.2;
879 if (rx<0) or (ry<0) then exit;
880 end;
881 multi := TBGRAMultishapeFiller.Create;
882 multi.Antialiasing := AntialiasingMode <> amOff;
883 multi.PolygonOrder := poLastOnTop;
884 multi.AliasingIncludeBottomRight := True;
885 if not NoBrush then
886 begin
887 if tex <> nil then
888 multi.AddEllipse(cx,cy,rx,ry,tex)
889 else
890 multi.AddEllipse(cx,cy,rx,ry,Brush.ActualColor);
891 end;
892 if not NoPen then
893 begin
894 ApplyPenStyle;
895 if (Pen.Style = psSolid) and multi.Antialiasing then
896 multi.AddEllipseBorder(cx,cy,rx,ry,w,Pen.ActualColor)
897 else
898 multi.AddPolygon(FBitmap.ComputeWidePolygon(ComputeEllipse(cx,cy,rx,ry),w),Pen.ActualColor);
899 end;
900 multi.Draw(FBitmap);
901 multi.Free;
902end;
903
904procedure TBGRACanvas.Ellipse(const bounds: TRect);
905begin
906 Ellipse(bounds.left,bounds.top,bounds.right,bounds.Bottom);
907end;
908
909procedure TBGRACanvas.Rectangle(x1, y1, x2, y2: integer; Filled: Boolean = True);
910var tx,ty: integer;
911 w: single;
912 tex: IBGRAScanner;
913 multi: TBGRAMultishapeFiller;
914begin
915 if NoPen and NoBrush then exit;
916 if not CheckRectangle(x1,y1,x2,y2,tx,ty) then exit;
917
918 if NoPen then
919 FillRect(x1,y1,x2-1,y2-1) //one pixel
920 else
921 begin
922 dec(x2);
923 dec(y2);
924
925 if (Pen.Style = psSolid) and not Filled then
926 begin
927 ApplyPenStyle;
928 FBitmap.RectangleAntialias(x1,y1,x2,y2,Pen.ActualColor,Pen.ActualWidth);
929 exit;
930 end;
931
932 tex := Brush.BuildTexture(FBitmap);
933
934 if (Pen.Style = psSolid) and (tex=nil) then
935 begin
936 ApplyPenStyle;
937 FBitmap.RectangleAntialias(x1,y1,x2,y2,Pen.ActualColor,Pen.ActualWidth,Brush.ActualColor);
938 exit;
939 end;
940
941 w := Pen.ActualWidth;
942 multi := TBGRAMultishapeFiller.Create;
943 multi.Antialiasing := AntialiasingMode <> amOff;
944 multi.PolygonOrder := poLastOnTop;
945 if not NoBrush and Filled then
946 begin
947 if tex <> nil then
948 multi.AddRectangle(x1,y1,x2,y2,tex)
949 else
950 multi.AddRectangle(x1,y1,x2,y2,Brush.ActualColor);
951 end;
952 if not NoPen then
953 begin
954 ApplyPenStyle;
955 if (Pen.Style = psSolid) and (Pen.JoinStyle = pjsMiter) then
956 multi.AddRectangleBorder(x1,y1,x2,y2,w,Pen.ActualColor)
957 else
958 multi.AddPolygon(FBitmap.ComputeWidePolygon(
959 [PointF(x1,y1),PointF(x2,y1),PointF(x2,y2),PointF(x1,y2)],w), Pen.ActualColor);
960 end;
961 multi.Draw(FBitmap);
962 multi.Free;
963 end;
964end;
965
966procedure TBGRACanvas.Rectangle(const bounds: TRect; Filled: Boolean = True);
967begin
968 Rectangle(bounds.left,bounds.top,bounds.right,bounds.Bottom, Filled);
969end;
970
971procedure TBGRACanvas.Frame(x1, y1, x2, y2: integer);
972begin
973 Rectangle(x1,y1,x2,y2,False);
974end;
975
976procedure TBGRACanvas.Frame(const bounds: TRect);
977begin
978 Rectangle(bounds,False);
979end;
980
981procedure TBGRACanvas.RoundRect(x1, y1, x2, y2: integer; dx,dy: integer);
982var tx,ty: integer;
983 w: single;
984 tex: IBGRAScanner;
985 multi: TBGRAMultishapeFiller;
986 x1f,y1f,x2f,y2f: single;
987begin
988 if NoPen and NoBrush then exit;
989 tex := Brush.BuildTexture(FBitmap);
990 if (AntialiasingMode = amOff) and not NoPen and (Pen.Style = psSolid) and (Pen.ActualWidth = 1) then
991 begin
992 BGRARoundRectAliased(FBitmap,x1,y1,x2,y2,dx,dy,Pen.ActualColor,Brush.ActualColor,tex);
993 exit;
994 end;
995 if not CheckRectangle(x1,y1,x2,y2,tx,ty) then exit;
996
997 dec(x2);
998 dec(y2);
999 w := Pen.ActualWidth;
1000 multi := TBGRAMultishapeFiller.Create;
1001 multi.Antialiasing := AntialiasingMode <> amOff;
1002 multi.PolygonOrder := poLastOnTop;
1003 if not NoBrush then
1004 begin
1005 if NoPen then
1006 begin
1007 x1f := x1-0.5;
1008 y1f := y1-0.5;
1009 x2f := x2+0.5;
1010 y2f := y2+0.5;
1011 end else
1012 begin
1013 x1f := x1;
1014 y1f := y1;
1015 x2f := x2;
1016 y2f := y2;
1017 end;
1018 if tex <> nil then
1019 multi.AddRoundRectangle(x1f,y1f,x2f,y2f,dx/2,dy/2,tex)
1020 else
1021 multi.AddRoundRectangle(x1f,y1f,x2f,y2f,dx/2,dy/2,Brush.ActualColor);
1022 end;
1023 if not NoPen then
1024 begin
1025 ApplyPenStyle;
1026 if (Pen.Style = psSolid) and (Pen.JoinStyle = pjsMiter) then
1027 multi.AddRoundRectangleBorder(x1,y1,x2,y2,dx/2,dy/2,w,Pen.ActualColor)
1028 else
1029 multi.AddPolygon(FBitmap.ComputeWidePolygon(ComputeRoundRect(x1,y1,x2,y2,dx/2,dy/2),w),Pen.ActualColor);
1030 end;
1031 multi.Draw(FBitmap);
1032 multi.Free;
1033end;
1034
1035procedure TBGRACanvas.RoundRect(const bounds: TRect; dx,dy: integer);
1036begin
1037 RoundRect(bounds.left,bounds.top,bounds.right,bounds.Bottom,dx,dy);
1038end;
1039
1040procedure TBGRACanvas.EllipseC(x, y, rx, ry: integer);
1041begin
1042 Ellipse (Rect(x-rx,y-ry,x+rx,y+ry));
1043end;
1044
1045procedure TBGRACanvas.FillRect(x1, y1, x2, y2: integer);
1046var
1047 tex: IBGRAScanner;
1048begin
1049 if NoBrush then exit;
1050 tex := Brush.BuildTexture(FBitmap);
1051 if tex <> nil then
1052 FBitmap.FillRect(x1,y1,x2,y2,tex,dmDrawWithTransparency)
1053 else
1054 FBitmap.FillRect(x1,y1,x2,y2,Brush.ActualColor,dmDrawWithTransparency);
1055end;
1056
1057procedure TBGRACanvas.FillRect(const bounds: TRect);
1058begin
1059 FillRect(bounds.left,bounds.top,bounds.right,bounds.Bottom);
1060end;
1061
1062procedure TBGRACanvas.FrameRect(x1, y1, x2, y2: integer; width: integer = 1);
1063var
1064 tex: IBGRAScanner;
1065 Temp: integer;
1066begin
1067 if (x1= x2) or (y1 =y2) or NoBrush then exit;
1068 if x1 > x2 then
1069 begin
1070 Temp := x1;
1071 x1 := x2;
1072 x2 := Temp;
1073 end;
1074 if y1 > y2 then
1075 begin
1076 Temp := y1;
1077 y1 := y2;
1078 y2 := Temp;
1079 end;
1080 dec(x2);
1081 dec(y2);
1082
1083 tex := Brush.BuildTexture(FBitmap);
1084 FBitmap.PenStyle := psSolid;
1085 FBitmap.JoinStyle := pjsMiter;
1086 if tex <> nil then
1087 FBitmap.RectangleAntialias(x1,y1,x2,y2,tex,width)
1088 else
1089 FBitmap.RectangleAntialias(x1,y1,x2,y2,Brush.ActualColor,width);
1090end;
1091
1092procedure TBGRACanvas.FrameRect(const bounds: TRect; width: integer = 1);
1093begin
1094 FrameRect(bounds.left,bounds.top,bounds.right,bounds.Bottom,width);
1095end;
1096
1097procedure TBGRACanvas.Frame3D(var bounds: TRect; width: integer;
1098 Style: TGraphicsBevelCut);
1099begin
1100 Frame3D(bounds,width,style,ColorToBGRA(clRgbBtnHighlight),ColorToBGRA(clRgbBtnShadow));
1101end;
1102
1103procedure TBGRACanvas.Frame3D(var bounds: TRect; width: integer;
1104 Style: TGraphicsBevelCut; LightColor: TBGRAPixel; ShadowColor: TBGRAPixel);
1105var temp: TBGRAPixel;
1106 multi: TBGRAMultishapeFiller;
1107 color1,color2: TBGRAPixel;
1108begin
1109 if width <= 0 then exit;
1110 color1 := LightColor;
1111 color2 := ShadowColor;
1112 if Style = bvLowered then
1113 begin
1114 temp := color1;
1115 color1 := color2;
1116 color2 := temp;
1117 end;
1118 if Style in [bvLowered,bvRaised] then
1119 begin
1120 multi := TBGRAMultishapeFiller.Create;
1121 multi.Antialiasing := AntialiasingMode <> amOff;
1122 multi.AddPolygon([PointF(bounds.Left-0.5,bounds.Top-0.5),PointF(bounds.Right-0.5,bounds.Top-0.5),
1123 PointF(bounds.Right-0.5-width,bounds.Top-0.5+width),PointF(bounds.Left-0.5+width,bounds.Top-0.5+width),
1124 PointF(bounds.Left-0.5+width,bounds.Bottom-0.5-width),PointF(bounds.Left-0.5,bounds.Bottom-0.5)],color1);
1125 multi.AddPolygon([PointF(bounds.Right-0.5,bounds.Bottom-0.5),PointF(bounds.Left-0.5,bounds.Bottom-0.5),
1126 PointF(bounds.Left-0.5+width,bounds.Bottom-0.5-width),PointF(bounds.Right-0.5-width,bounds.Bottom-0.5-width),
1127 PointF(bounds.Right-0.5-width,bounds.Top-0.5+width),PointF(bounds.Right-0.5,bounds.Top-0.5)],color2);
1128 multi.Draw(FBitmap);
1129 multi.Free;
1130 end;
1131 InflateRect(bounds,-width,-width);
1132end;
1133
1134procedure TBGRACanvas.GradientFill(ARect: TRect; AStart, AStop: TColor;
1135 ADirection: TGradientDirection; GammaCorrection: Boolean = false);
1136var
1137 Count: Integer;
1138
1139 procedure NotGammaCorrected;
1140 var
1141 c: TBGRAPixel;
1142 I: Integer;
1143 BDiff,GDiff,RDiff: Integer;
1144 BStop,BStart: Byte;
1145 GStop,GStart: Byte;
1146 RStop,RStart: Byte;
1147 begin
1148 RedGreenBlue(ColorToRGB(AStart), RStart, GStart, BStart);
1149 RedGreenBlue(ColorToRGB(AStop), RStop, GStop, BStop);
1150
1151 RDiff := RStop - RStart;
1152 GDiff := GStop - GStart;
1153 BDiff := BStop - BStart;
1154
1155 for I := 0 to Count-1 do
1156 begin
1157 c := BGRA(RStart + (i * RDiff) div Count,
1158 GStart + (i * GDiff) div Count,
1159 BStart + (i * BDiff) div Count);
1160
1161 if ADirection = gdHorizontal then
1162 FBitmap.SetVertLine(ARect.Left+I,ARect.Top,ARect.Bottom-1,c)
1163 else
1164 FBitmap.SetHorizLine(ARect.Left,ARect.Top+I,ARect.Right-1,c);
1165 end;
1166 end;
1167
1168 procedure GammaCorrected;
1169 var
1170 ec: TExpandedPixel;
1171 c: TBGRAPixel;
1172 I: Integer;
1173 BDiff,GDiff,RDiff: Integer;
1174 CStart,CStop: TExpandedPixel;
1175 begin
1176 CStart := GammaExpansion(ColorToBGRA(ColorToRGB(AStart)));
1177 CStop := GammaExpansion(ColorToBGRA(ColorToRGB(AStop)));
1178
1179 RDiff := CStop.red - CStart.red;
1180 GDiff := CStop.green - CStart.green;
1181 BDiff := CStop.blue - CStart.blue;
1182
1183 for I := 0 to Count-1 do
1184 begin
1185 ec.red := CStart.red + (i * RDiff) div Count;
1186 ec.green := CStart.green + (i * GDiff) div Count;
1187 ec.blue := CStart.blue + (i * BDiff) div Count;
1188 ec.alpha := $ffff;
1189 c := GammaCompression(ec);
1190
1191 if ADirection = gdHorizontal then
1192 FBitmap.SetVertLine(ARect.Left+I,ARect.Top,ARect.Bottom-1,c)
1193 else
1194 FBitmap.SetHorizLine(ARect.Left,ARect.Top+I,ARect.Right-1,c);
1195 end;
1196 end;
1197
1198begin
1199 with ARect do
1200 if (Right <= Left) or (Bottom <= Top) then
1201 Exit;
1202
1203 if ADirection = gdVertical then
1204 Count := ARect.Bottom - ARect.Top
1205 else
1206 Count := ARect.Right - ARect.Left;
1207
1208 if GammaCorrection then
1209 GammaCorrected else
1210 NotGammaCorrected;
1211end;
1212
1213procedure TBGRACanvas.FloodFill(X, Y: Integer; FillColor: TColor;
1214 FillStyle: TFillStyle);
1215begin
1216 FloodFill(X,Y,ColorToBGRA(FillColor,255),FillStyle);
1217end;
1218
1219procedure TBGRACanvas.FloodFill(X, Y: Integer; FillColor: TBGRAPixel;
1220 FillStyle: TFillStyle);
1221var
1222 tex: IBGRAScanner;
1223 texRepeat,mask: TBGRACustomBitmap;
1224begin
1225 tex := Brush.BuildTexture(FBitmap);
1226 if FillStyle = fsSurface then
1227 begin
1228 if FBitmap.GetPixel(X,Y) <> FillColor then exit;
1229 if tex <> nil then
1230 begin
1231 texRepeat := FBitmap.NewBitmap(FBitmap.Width,FBitmap.Height);
1232 texRepeat.Fill(tex);
1233 mask := FBitmap.NewBitmap(FBitmap.Width,FBitmap.Height);
1234 mask.Fill(BGRABlack);
1235 FBitmap.ParallelFloodFill(X,Y,mask,BGRAWhite,fmSet);
1236 texRepeat.ApplyMask(mask);
1237 mask.Free;
1238 FBitmap.PutImage(0,0,texRepeat,dmDrawWithTransparency);
1239 texRepeat.Free;
1240 end
1241 else
1242 if Brush.ActualColor.alpha <> 0 then
1243 FBitmap.FloodFill(X,Y,Brush.ActualColor,fmDrawWithTransparency);
1244 end;
1245 //fsBorder not handled
1246end;
1247
1248procedure TBGRACanvas.FloodFill(X, Y: Integer);
1249begin
1250 FloodFill(X,Y,FBitmap.GetPixel(X,Y),fsSurface);
1251end;
1252
1253procedure TBGRACanvas.Polygon(const APoints: array of TPoint);
1254begin
1255 Polygon(@APoints[0],length(APoints),FillMode = fmWinding);
1256end;
1257
1258procedure TBGRACanvas.Polygon(const Points: array of TPoint; Winding: Boolean;
1259 StartIndex: Integer; NumPts: Integer);
1260begin
1261 if (StartIndex < 0) or (StartIndex >= length(Points)) then exit;
1262 if NumPts < 0 then NumPts := length(Points)-StartIndex;
1263 Polygon(@Points[StartIndex],NumPts,Winding);
1264end;
1265
1266procedure TBGRACanvas.Polygon(Points: PPoint; NumPts: Integer; Winding: boolean);
1267var
1268 ptsF: array of TPointF;
1269 i: Integer;
1270 Ofs: TPointF;
1271begin
1272 if NoPen and NoBrush then exit;
1273 if NoPen then Ofs := PointF(-0.5,-0.5) else Ofs := PointF(0,0);
1274 setlength(ptsF, NumPts);
1275 for i := 0 to NumPts-1 do
1276 begin
1277 ptsF[i] := PointF(Points^.x,Points^.y)+Ofs;
1278 inc(Points);
1279 end;
1280 PolygonF(ptsF,Winding);
1281end;
1282
1283procedure TBGRACanvas.PolygonF(const APoints: array of TPointF);
1284begin
1285 PolygonF(APoints, FillMode = fmWinding);
1286end;
1287
1288procedure TBGRACanvas.PolygonF(const APoints: array of TPointF; Winding: Boolean; FillOnly: Boolean = False);
1289var
1290 multi: TBGRAMultishapeFiller;
1291 tex: IBGRAScanner;
1292begin
1293 if NoPen and NoBrush then exit;
1294
1295 multi := TBGRAMultishapeFiller.Create;
1296 multi.Antialiasing := AntialiasingMode <> amOff;
1297 if Winding then multi.FillMode := fmWinding else
1298 multi.FillMode := fmAlternate;
1299 multi.PolygonOrder := poLastOnTop;
1300
1301 if not NoBrush then
1302 begin
1303 tex := Brush.BuildTexture(FBitmap);
1304 if tex <> nil then
1305 multi.AddPolygon(APoints,tex)
1306 else
1307 multi.AddPolygon(APoints,Brush.ActualColor);
1308 end;
1309
1310 if not NoPen and not FillOnly then
1311 begin
1312 ApplyPenStyle;
1313 multi.AddPolygon(FBitmap.ComputeWidePolygon(APoints,Pen.ActualWidth),Pen.ActualColor);
1314 end;
1315 multi.Draw(FBitmap);
1316 multi.Free
1317end;
1318
1319procedure TBGRACanvas.Polyline(const APoints: array of TPoint);
1320begin
1321 Polyline(@APoints[0],length(APoints));
1322end;
1323
1324procedure TBGRACanvas.Polyline(const Points: array of TPoint; StartIndex: Integer; NumPts: Integer);
1325begin
1326 if (StartIndex < 0) or (StartIndex >= length(Points)) then exit;
1327 if NumPts < 0 then NumPts := length(Points)-StartIndex;
1328 Polyline(@Points[StartIndex],NumPts);
1329end;
1330
1331procedure TBGRACanvas.Polyline(Points: PPoint; NumPts: Integer);
1332var
1333 i: Integer;
1334 ptsF: array of TPointF;
1335 oldPos: TPoint;
1336begin
1337 if NoPen or (NumPts <= 0) then exit;
1338
1339 if (Pen.Style = psSolid) and (Pen.ActualWidth = 1) then
1340 begin
1341 oldPos := FPenPos;
1342 MoveTo(Points^.x,Points^.y);
1343 for i := 1 to NumPts-1 do
1344 begin
1345 inc(Points);
1346 LineTo(Points^.x,Points^.y);
1347 end;
1348 FPenPos := oldPos;
1349 exit;
1350 end;
1351
1352 setlength(ptsF, NumPts);
1353 for i := 0 to NumPts-1 do
1354 begin
1355 ptsF[i] := PointF(Points^.x,Points^.y);
1356 inc(Points);
1357 end;
1358 PolylineF(ptsF);
1359end;
1360
1361procedure TBGRACanvas.PolylineF(const APoints: array of TPointF);
1362var ptsF: Array of TPointF;
1363begin
1364 if NoPen then exit;
1365 ApplyPenStyle;
1366 FBitmap.FillMode := fmWinding;
1367 ptsF := FBitmap.ComputeWidePolyline(APoints,Pen.ActualWidth);
1368 if AntialiasingMode = amOff then
1369 FBitmap.FillPoly(ptsF,Pen.ActualColor,dmDrawWithTransparency) else
1370 FBitmap.FillPolyAntialias(ptsF,Pen.ActualColor);
1371end;
1372
1373procedure TBGRACanvas.PolyBezier(Points: PPoint; NumPts: Integer;
1374 Filled: boolean; Continuous: boolean);
1375var
1376 beziers: array of TCubicBezierCurve;
1377 nbBeziers,i: integer;
1378 PrevPt: TPointF;
1379 spline: array of TPointF;
1380begin
1381 if NumPts < 4 then exit;
1382 if Continuous then
1383 begin
1384 nbBeziers := 1+(NumPts-4) div 3;
1385 setlength(beziers, nbBeziers);
1386 PrevPt := PointF(Points^.x,Points^.y);
1387 inc(Points);
1388 for i := 0 to nbBeziers-1 do
1389 begin
1390 beziers[i].p1 := prevPt;
1391 beziers[i].c1 := PointF(Points^.x,Points^.y);
1392 inc(Points);
1393 beziers[i].c2 := PointF(Points^.x,Points^.y);
1394 inc(Points);
1395 beziers[i].p2 := PointF(Points^.x,Points^.y);
1396 inc(Points);
1397 prevPt := beziers[i].p2;
1398 end;
1399 end else
1400 begin
1401 nbBeziers := NumPts div 4;
1402 setlength(beziers, nbBeziers);
1403 for i := 0 to nbBeziers-1 do
1404 begin
1405 beziers[i].p1 := PointF(Points^.x,Points^.y);
1406 inc(Points);
1407 beziers[i].c1 := PointF(Points^.x,Points^.y);
1408 inc(Points);
1409 beziers[i].c2 := PointF(Points^.x,Points^.y);
1410 inc(Points);
1411 beziers[i].p2 := PointF(Points^.x,Points^.y);
1412 inc(Points);
1413 end;
1414 end;
1415 spline := ComputeBezierSpline(beziers);
1416 if Filled then
1417 PolygonF(spline) else
1418 PolylineF(spline);
1419end;
1420
1421procedure TBGRACanvas.PolyBezier(const Points: array of TPoint;
1422 Filled: boolean; Continuous: boolean);
1423begin
1424 PolyBezier(@Points[0],length(Points),Filled,Continuous);
1425end;
1426
1427procedure TBGRACanvas.Draw(X, Y: Integer; SrcBitmap: TBGRACustomBitmap);
1428begin
1429 FBitmap.PutImage(X,Y,SrcBitmap,dmDrawWithTransparency);
1430end;
1431
1432procedure TBGRACanvas.Draw(X, Y: Integer; SrcBitmap: TBitmap);
1433begin
1434 FBitmap.PutImage(X,Y,SrcBitmap,dmDrawWithTransparency);
1435end;
1436
1437procedure TBGRACanvas.CopyRect(X, Y: Integer; SrcBitmap: TBGRACustomBitmap;
1438 SrcRect: TRect);
1439begin
1440 FBitmap.PutImagePart(X,Y,SrcBitmap,SrcRect,dmDrawWithTransparency);
1441end;
1442
1443procedure TBGRACanvas.StretchDraw(DestRect: TRect; SrcBitmap: TBGRACustomBitmap; HorizFlip: Boolean = false; VertFlip: Boolean = false);
1444var Stretched: TBGRACustomBitmap;
1445 temp: Integer;
1446begin
1447 with DestRect do
1448 begin
1449 if (Left= Right) or (Top =Bottom) then exit;
1450 if Left > Right then
1451 begin
1452 Temp := Left;
1453 Left := Right+1;
1454 Right := Temp+1;
1455 HorizFlip := not HorizFlip;
1456 end;
1457 if Top > Bottom then
1458 begin
1459 Temp := Top;
1460 Top := Bottom+1;
1461 Bottom := Temp+1;
1462 VertFlip := not VertFlip;
1463 end;
1464 end;
1465 if (DestRect.Right-DestRect.Left <> SrcBitmap.Width) or
1466 (DestRect.Bottom-DestRect.Top <> SrcBitmap.Height) or
1467 HorizFlip or VertFlip then
1468 begin
1469 if AntialiasingMode = amOff then
1470 Stretched := SrcBitmap.Resample(DestRect.Right-DestRect.Left,DestRect.Bottom-DestRect.Top,rmSimpleStretch) else
1471 Stretched := SrcBitmap.Resample(DestRect.Right-DestRect.Left,DestRect.Bottom-DestRect.Top,rmFineResample);
1472 if HorizFlip then Stretched.HorizontalFlip;
1473 if VertFlip then Stretched.VerticalFlip;
1474 FBitmap.PutImage(DestRect.Left,DestRect.Top,Stretched,dmDrawWithTransparency);
1475 Stretched.Free;
1476 end else
1477 FBitmap.PutImage(DestRect.Left,DestRect.Top,SrcBitmap,dmDrawWithTransparency);
1478end;
1479
1480procedure TBGRACanvas.DrawFocusRect(bounds: TRect);
1481var
1482 temp: Integer;
1483 xb,yb: integer;
1484 c: TBGRAPixel;
1485begin
1486 c := Brush.ActualColor;
1487 if (c.red = 0) and (c.Green =0) and (c.Blue =0) then exit;
1488 c.alpha := 0;
1489 with bounds do
1490 begin
1491 if (Left= Right) or (Top =Bottom) then exit;
1492 if Left > Right then
1493 begin
1494 Temp := Left;
1495 Left := Right;
1496 Right := Temp;
1497 end;
1498 if Top > Bottom then
1499 begin
1500 Temp := Top;
1501 Top := Bottom;
1502 Bottom := Temp;
1503 end;
1504 dec(Right);
1505 dec(Bottom);
1506 for xb := max(FBitmap.ClipRect.Left, bounds.Left+1) to min(FBitmap.ClipRect.Right-1,bounds.Right-1) do
1507 begin
1508 if odd(xb) xor odd(Top) then FBitmap.XorPixel(xb,Top,c);
1509 if odd(xb) xor odd(Bottom) then FBitmap.XorPixel(xb,Bottom,c);
1510 end;
1511 for yb := max(FBitmap.ClipRect.Top, bounds.Top) to min(FBitmap.ClipRect.Bottom-1,bounds.Bottom) do
1512 begin
1513 if odd(yb) xor odd(Left) then FBitmap.XorPixel(Left,yb,c);
1514 if odd(yb) xor odd(Right) then FBitmap.XorPixel(Right,yb,c);
1515 end;
1516 end;
1517end;
1518
1519procedure TBGRACanvas.CopyRect(Dest: TRect; SrcBmp: TBGRACustomBitmap;
1520 Source: TRect);
1521var TempBmp: TBGRACustomBitmap;
1522 Temp: Integer;
1523 FlipHoriz,FlipVert: Boolean;
1524begin
1525 if (Dest.Right-Dest.Left = Source.Right-Source.Left) and (Dest.Bottom-Dest.Top = Source.Bottom-Source.Top) and
1526 (Dest.Right > Dest.Left) and (Dest.Bottom > Dest.Top) then
1527 begin
1528 CopyRect(Dest.Left,Dest.Top, SrcBmp, Source);
1529 exit;
1530 end;
1531 if (Source.Left = Source.Right) or (Source.Bottom = Source.Top) or
1532 (Dest.Left = Dest.Right) or (Dest.Bottom = Dest.Top) then exit;
1533 if Source.Left > Source.Right then
1534 begin
1535 Temp := Source.Left;
1536 Source.Left := Source.Right+1;
1537 Source.Right := Temp+1;
1538 FlipHoriz := True;
1539 end else
1540 FlipHoriz := false;
1541 if Source.Top > Source.Bottom then
1542 begin
1543 Temp := Source.Top;
1544 Source.Top := Source.Bottom+1;
1545 Source.Bottom := Temp+1;
1546 FlipVert := True;
1547 end else
1548 FlipVert := false;
1549 TempBmp := SrcBmp.GetPart(Source);
1550 StretchDraw(Dest,TempBmp,FlipHoriz,FlipVert);
1551 TempBmp.Free;
1552end;
1553
1554procedure TBGRACanvas.TextOut(X, Y: Integer; const Text: String);
1555var size: TSize;
1556 c,s: single;
1557begin
1558 ApplyFont;
1559 if DrawFontBackground then
1560 begin
1561 size := TextExtent(Text);
1562 c := cos(Font.Orientation*Pi/1800);
1563 s := -sin(Font.Orientation*Pi/1800);
1564 PolygonF([PointF(X,Y),PointF(X+c*size.cx,Y+s*size.cx),
1565 PointF(X+c*size.cx-s*size.cy,Y+s*size.cx+c*size.cy),
1566 PointF(X-s*size.cy,Y+c*size.cy)],False,True);
1567 end;
1568 if Font.Texture <> nil then
1569 FBitmap.TextOut(x,y,Text,Font.Texture) else
1570 FBitmap.TextOut(x,y,Text,Font.BGRAColor);
1571end;
1572
1573procedure TBGRACanvas.TextRect(const ARect: TRect; X, Y: integer;
1574 const Text: string);
1575begin
1576 ApplyFont;
1577 if Font.Texture <> nil then
1578 FBitmap.TextRect(ARect,x,y,Text,self.TextStyle,Font.Texture) else
1579 FBitmap.TextRect(ARect,x,y,Text,self.TextStyle,Font.BGRAColor);
1580end;
1581
1582procedure TBGRACanvas.TextRect(ARect: TRect; X, Y: integer; const Text: string;
1583 const Style: TTextStyle);
1584begin
1585 ApplyFont;
1586 if Font.Texture <> nil then
1587 FBitmap.TextRect(ARect,x,y,Text,Style,Font.Texture) else
1588 FBitmap.TextRect(ARect,x,y,Text,Style,Font.BGRAColor);
1589end;
1590
1591function TBGRACanvas.TextExtent(const Text: string): TSize;
1592begin
1593 ApplyFont;
1594 result := FBitmap.TextSize(Text);
1595end;
1596
1597{$hints off}
1598function TBGRACanvas.TextHeight(const Text: string): Integer;
1599begin
1600 ApplyFont;
1601 result := FBitmap.TextSize(Text).cy;
1602end;
1603{$hints on}
1604
1605function TBGRACanvas.TextWidth(const Text: string): Integer;
1606begin
1607 ApplyFont;
1608 result := FBitmap.TextSize(Text).cx;
1609end;
1610
1611end.
1612
Note: See TracBrowser for help on using the repository browser.