Ignore:
Timestamp:
Apr 17, 2019, 12:58:41 AM (5 years ago)
Author:
chronos
Message:
  • Modified: Propagate project build mode options to used packages.
  • Added: Check memory leaks using heaptrc.
  • Modified: Update BGRABitmap package.
Location:
GraphicTest
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • GraphicTest

    • Property svn:ignore
      •  

        old new  
        88GraphicTest.lps
        99GraphicTest.dbg
         10heaptrclog.trc
  • GraphicTest/Packages/bgrabitmap/bgratypewriter.pas

    r494 r521  
    3535  end;
    3636
    37   TGlyphPointCurveMode= (cmAuto, cmCurve, cmAngle);
    38 
     37  TGlyphPointCurveMode= TEasyBezierCurveMode;
     38
     39const
     40  cmAuto = TEasyBezierCurveMode.cmAuto;
     41  cmCurve = TEasyBezierCurveMode.cmCurve;
     42  cmAngle = TEasyBezierCurveMode.cmAngle;
     43
     44type
    3945  { TBGRAPolygonalGlyph }
    4046
    4147  TBGRAPolygonalGlyph = class(TBGRAGlyph)
    4248  private
     49    function GetClosed: boolean;
     50    function GetMinimumDotProduct: single;
     51    function GetPoint(AIndex: integer): TPointF;
     52    function GetPointCount: integer;
     53    procedure SetClosed(AValue: boolean);
     54    procedure SetMinimumDotProduct(AValue: single);
     55    procedure SetPoint(AIndex: integer; AValue: TPointF);
    4356    procedure SetQuadraticCurves(AValue: boolean);
    4457  protected
    4558    FQuadraticCurves: boolean;
    46     Points: array of TPointF;
    47     CurveMode: array of TGlyphPointCurveMode;
    48     Curves: array of record
    49       isCurvedToNext,isCurvedToPrevious: boolean;
    50       Center,ControlPoint,NextCenter: TPointF;
    51     end;
    52     function MaybeCurve(start1,end1,start2,end2: integer): boolean;
    53     procedure ComputeQuadraticCurves;
     59    FEasyBezier: TEasyBezierCurve;
    5460    function ContentSize: integer; override;
    5561    function HeaderName: string; override;
    5662    procedure WriteContent(AStream: TStream); override;
    5763    procedure ReadContent(AStream: TStream); override;
     64    function PointTransformMatrix(APoint: PPointF; AData: pointer): TPointF;
    5865    procedure Init;
    5966  public
    6067    Offset: TPointF;
    61     Closed: boolean;
    62     MinimumDotProduct: single;
    6368    constructor Create(AIdentifier: string); override;
    6469    constructor Create(AStream: TStream); override;
     70    constructor Create(AStream: TStream; AQuadratic: boolean);
    6571    procedure SetPoints(const APoints: array of TPointF); overload;
    6672    procedure SetPoints(const APoints: array of TPointF; const ACurveMode: array of TGlyphPointCurveMode); overload;
    6773    procedure Path(ADest: IBGRAPath; AMatrix: TAffineMatrix); override;
    6874    property QuadraticCurves: boolean read FQuadraticCurves write SetQuadraticCurves;
     75    property Closed: boolean read GetClosed write SetClosed;
     76    property MinimumDotProduct: single read GetMinimumDotProduct write SetMinimumDotProduct;
     77    property Point[AIndex: integer]: TPointF read GetPoint write SetPoint;
     78    property PointCount: integer read GetPointCount;
    6979  end;
    7080
     
    193203{ TBGRAPolygonalGlyph }
    194204
     205function TBGRAPolygonalGlyph.GetClosed: boolean;
     206begin
     207  result := FEasyBezier.Closed;
     208end;
     209
     210function TBGRAPolygonalGlyph.GetMinimumDotProduct: single;
     211begin
     212  result := FEasyBezier.MinimumDotProduct;
     213end;
     214
     215function TBGRAPolygonalGlyph.GetPoint(AIndex: integer): TPointF;
     216begin
     217  result := FEasyBezier.Point[AIndex];
     218end;
     219
     220function TBGRAPolygonalGlyph.GetPointCount: integer;
     221begin
     222  result := FEasyBezier.PointCount;
     223end;
     224
     225procedure TBGRAPolygonalGlyph.SetClosed(AValue: boolean);
     226begin
     227  FEasyBezier.Closed := AValue;
     228end;
     229
     230procedure TBGRAPolygonalGlyph.SetMinimumDotProduct(AValue: single);
     231begin
     232  FEasyBezier.MinimumDotProduct := AValue;
     233end;
     234
     235procedure TBGRAPolygonalGlyph.SetPoint(AIndex: integer; AValue: TPointF);
     236begin
     237  FEasyBezier.Point[AIndex] := AValue;
     238end;
     239
    195240procedure TBGRAPolygonalGlyph.SetQuadraticCurves(AValue: boolean);
    196241begin
    197242  if FQuadraticCurves=AValue then Exit;
    198243  FQuadraticCurves:=AValue;
    199   Curves := nil;
    200 end;
    201 
    202 function TBGRAPolygonalGlyph.MaybeCurve(start1,end1,start2,end2: integer): boolean;
    203 var
    204   u,v: TPointF;
    205   lu,lv: single;
    206 begin
    207   if (start1=-1) or (end1=-1) or (start2=-1) or (end2=-1) then
    208   begin
    209     result := false;
    210     exit;
    211   end;
    212   u := pointF(points[end1].x - points[start1].x, points[end1].y - points[start1].y);
    213   lu := sqrt(u*u);
    214   if lu <> 0 then u *= 1/lu;
    215   v := pointF(points[end2].x - points[start2].x, points[end2].y - points[start2].y);
    216   lv := sqrt(v*v);
    217   if lv <> 0 then v *= 1/lv;
    218 
    219   result := u*v > MinimumDotProduct;
    220 end;
    221 
    222 procedure TBGRAPolygonalGlyph.ComputeQuadraticCurves;
    223 var
    224   i,FirstPointIndex,NextPt,NextPt2: integer;
    225 begin
    226   setlength(Curves, length(points));
    227   FirstPointIndex := 0;
    228   for i := 0 to high(points) do
    229     Curves[i].isCurvedToPrevious := false;
    230   for i := 0 to high(points) do
    231   begin
    232     Curves[i].isCurvedToNext := false;
    233     Curves[i].Center := EmptyPointF;
    234     Curves[i].ControlPoint := EmptyPointF;
    235     Curves[i].NextCenter := EmptyPointF;
    236 
    237     if IsEmptyPointF(Points[i]) then
    238     begin
    239       FirstPointIndex := i+1;
    240     end else
    241     begin
    242       NextPt := i+1;
    243       if (NextPt = length(points)) or isEmptyPointF(points[NextPt]) then NextPt := FirstPointIndex;
    244       NextPt2 := NextPt+1;
    245       if (NextPt2 = length(points)) or isEmptyPointF(points[NextPt2]) then NextPt2 := FirstPointIndex;
    246 
    247       Curves[i].Center := (points[i]+points[NextPt])*0.5;
    248       Curves[i].NextCenter := (points[NextPt]+points[NextPt2])*0.5;
    249       Curves[i].ControlPoint := points[NextPt];
    250 
    251       if (i < high(points)-1) or Closed then
    252       begin
    253         case CurveMode[nextPt] of
    254           cmAuto: Curves[i].isCurvedToNext:= MaybeCurve(i,NextPt,NextPt,NextPt2);
    255           cmCurve: Curves[i].isCurvedToNext:= true;
    256           else Curves[i].isCurvedToNext:= false;
    257         end;
    258         Curves[NextPt].isCurvedToPrevious := Curves[i].isCurvedToNext;
    259       end;
    260     end;
    261   end;
    262244end;
    263245
    264246function TBGRAPolygonalGlyph.ContentSize: integer;
    265247begin
    266   Result:= (inherited ContentSize) + sizeof(single)*2 + 4 + sizeof(single)*2*length(Points);
     248  Result:= (inherited ContentSize) + sizeof(single)*2 + 4 + sizeof(single)*2*PointCount;
    267249end;
    268250
    269251function TBGRAPolygonalGlyph.HeaderName: string;
    270252begin
    271   Result:='TBGRAPolygonalGlyph';
     253  if FQuadraticCurves then
     254    Result:='TBGRAEasyBezierGlyph'
     255  else
     256    Result:='TBGRAPolygonalGlyph'
    272257end;
    273258
     
    277262  inherited WriteContent(AStream);
    278263  LEWritePointF(AStream, Offset);
    279   LEWriteLongint(AStream,length(Points));
    280   for i := 0 to high(Points) do
    281     LEWritePointF(AStream, Points[i]);
     264  LEWriteLongint(AStream,PointCount);
     265  for i := 0 to PointCount-1 do
     266    LEWritePointF(AStream, FEasyBezier.Point[i]);
     267  if FQuadraticCurves then
     268    for i := 0 to PointCount-1 do
     269      LEWriteLongint(AStream, ord(FEasyBezier.CurveMode[i]));
    282270end;
    283271
     
    285273var i: integer;
    286274  tempPts: array of TPointF;
     275  flags: LongInt;
    287276begin
    288277  inherited ReadContent(AStream);
     
    292281    tempPts[i] := LEReadPointF(AStream);
    293282  SetPoints(tempPts);
     283  if FQuadraticCurves then
     284  begin
     285    for i := 0 to high(tempPts) do
     286    begin
     287      flags := LEReadLongint(AStream);
     288      FEasyBezier.CurveMode[i] := TEasyBezierCurveMode(flags and 255);
     289    end;
     290  end;
     291end;
     292
     293function TBGRAPolygonalGlyph.PointTransformMatrix(APoint: PPointF;
     294  AData: pointer): TPointF;
     295begin
     296  result := TAffineMatrix(AData^) * APoint^;
    294297end;
    295298
    296299procedure TBGRAPolygonalGlyph.Init;
    297300begin
     301  FEasyBezier.Init;
    298302  Closed := True;
    299   MinimumDotProduct := 0.707;
     303  Offset := PointF(0,0);
     304  FQuadraticCurves:= False;
    300305end;
    301306
    302307constructor TBGRAPolygonalGlyph.Create(AIdentifier: string);
    303308begin
     309  Init;
    304310  inherited Create(AIdentifier);
    305   Offset := PointF(0,0);
     311end;
     312
     313constructor TBGRAPolygonalGlyph.Create(AStream: TStream);
     314begin
    306315  Init;
    307 end;
    308 
    309 constructor TBGRAPolygonalGlyph.Create(AStream: TStream);
    310 begin
    311316  inherited Create(AStream);
     317end;
     318
     319constructor TBGRAPolygonalGlyph.Create(AStream: TStream; AQuadratic: boolean);
     320begin
    312321  Init;
     322  FQuadraticCurves:= AQuadratic;
     323  inherited Create(AStream);
    313324end;
    314325
    315326procedure TBGRAPolygonalGlyph.SetPoints(const APoints: array of TPointF);
    316 var i: integer;
    317 begin
    318   SetLength(Points,length(APoints));
    319   for i := 0 to high(points) do
    320     points[i] := APoints[i];
    321   setlength(CurveMode, length(APoints));
    322   for i := 0 to high(CurveMode) do
    323     CurveMode[i] := cmAuto;
    324   Curves := nil;
     327begin
     328  FEasyBezier.SetPoints(APoints, cmAuto);
    325329end;
    326330
    327331procedure TBGRAPolygonalGlyph.SetPoints(const APoints: array of TPointF;
    328332  const ACurveMode: array of TGlyphPointCurveMode);
    329 var i: integer;
    330333begin
    331334  if length(APoints) <> length(ACurveMode) then
    332335    raise exception.Create('Dimension mismatch');
    333   SetLength(Points,length(APoints));
    334   for i := 0 to high(points) do
    335     points[i] := APoints[i];
    336   setlength(CurveMode, length(ACurveMode));
    337   for i := 0 to high(CurveMode) do
    338     CurveMode[i] := ACurveMode[i];
    339   Curves := nil;
     336  FEasyBezier.SetPoints(APoints, ACurveMode);
    340337end;
    341338
     
    343340var i: integer;
    344341  nextMove: boolean;
    345   startCoord: TPointF;
    346 
    347 begin
    348   if Points = nil then exit;
    349 
    350   if (Curves = nil) and FQuadraticCurves then ComputeQuadraticCurves;
    351   nextMove := true;
     342begin
    352343  AMatrix := AMatrix*AffineMatrixTranslation(Offset.X,Offset.Y);
    353 
    354   for i := 0 to high(Points) do
    355     if isEmptyPointF(Points[i]) then
    356     begin
    357       if not nextMove then ADest.closePath;
    358       nextMove := true;
    359     end else
    360     if FQuadraticCurves then
    361     begin
    362       with Curves[i] do
     344  if not FQuadraticCurves then
     345  begin
     346    nextMove := true;
     347    for i := 0 to PointCount-1 do
     348      if isEmptyPointF(Point[i]) then
     349      begin
     350        if not nextMove and Closed then ADest.closePath;
     351        nextMove := true;
     352      end else
    363353      begin
    364354        if nextMove then
    365355        begin
    366           if not isCurvedToPrevious then
    367             startCoord := Points[i]
    368           else
    369             startCoord := Center;
    370           ADest.moveTo(AMatrix*startCoord);
     356          ADest.moveTo(AMatrix*Point[i]);
    371357          nextMove := false;
    372358        end else
    373           if not isCurvedToPrevious then
    374             ADest.lineTo(AMatrix*Points[i]);
    375 
    376         if isCurvedToNext then
    377         begin
    378           if not isCurvedToPrevious then ADest.lineTo(AMatrix*Center);
    379           ADest.quadraticCurveTo(AMatrix*ControlPoint,AMatrix*NextCenter);
    380         end;
     359          ADest.lineTo(AMatrix*Point[i]);
    381360      end;
    382     end else
    383     begin
    384       if nextMove then
    385       begin
    386         ADest.moveTo(AMatrix*Points[i]);
    387         nextMove := false;
    388       end else
    389       begin
    390         ADest.lineTo(AMatrix*Points[i]);
    391       end;
    392     end;
    393   if not nextmove then
    394     ADest.closePath;
     361    if not nextmove and Closed then ADest.closePath;
     362  end else
     363    FEasyBezier.CopyToPath(ADest, @PointTransformMatrix, @AMatrix);
    395364end;
    396365
     
    473442  if lName = 'TBGRAPolygonalGlyph' then
    474443    result := TBGRAPolygonalGlyph.Create(AStream)
     444  else if lName = 'TBGRAEasyBezierGlyph' then
     445    result := TBGRAPolygonalGlyph.Create(AStream, true)
    475446  else if lName = 'TBGRAGlyph' then
    476447    result := TBGRAGlyph.Create(AStream)
Note: See TracChangeset for help on using the changeset viewer.