{
Implements support for drawing to the LCL TCanvas via AggPas

License: The same modified LGPL as the Free Pascal RTL
         See the file COPYING.modifiedLGPL for more details

AUTHORS: Felipe Monteiro de Carvalho
}
unit fpvectorial2aggpas;

{$ifdef fpc}
  {$mode objfpc}{$h+}
{$endif}

{$define USE_CANVAS_CLIP_REGION}
{.$define DEBUG_CANVAS_CLIP_REGION}

{.$define FPVECTORIAL_DEBUG_DIMENSIONS}
{.$define FPVECTORIAL_TOCANVAS_DEBUG}
{.$define FPVECTORIAL_DEBUG_BLOCKS}
{.$define FPVECTORIAL_AUTOFIT_DEBUG}
{.$define FPVECTORIAL_SUPPORT_LAZARUS_1_6}
// visual debugs
{.$define FPVECTORIAL_TOCANVAS_ELLIPSE_VISUALDEBUG}
{.$define FPVECTORIAL_RENDERINFO_VISUALDEBUG}

interface

uses
  Classes, SysUtils, Math, TypInfo, contnrs, Types,
  // FCL-Image
  FPCanvas, FPImage, FPWriteBMP,
  // lazutils
  GraphType, LazUTF8, laz2_dom,
  // LCL
  LazRegions, Graphics, LCLIntf, LCLType, IntfGraphics, InterfaceBase,
  // AggPas
  agg_fpimage, Agg_LCL,
  // fpvectorial
  fpvutils, fpvectorial;

type

  { TFPVAggPasRenderer }

  TFPVAggPasRenderer = class(TvRenderer)
  private
    Bitmap: TBitmap;
    AggLCLCanvas: TAggLCLCanvas;
  public
    procedure BeginRender(var ARenderInfo: TvRenderInfo; ADoDraw: Boolean); override;
    procedure EndRender(var ARenderInfo: TvRenderInfo; ADoDraw: Boolean); override;
    // TPath
    procedure TPath_Render(var ARenderInfo: TvRenderInfo; ADoDraw: Boolean; APath: TPath); override;
  end;

implementation


{ TFPVAggPasRenderer }

procedure TFPVAggPasRenderer.BeginRender(var ARenderInfo: TvRenderInfo; ADoDraw: Boolean);
var
  HasFont: Boolean;
  FontFilename: String;
begin
  Bitmap := TBitmap.Create;
  AggLCLCanvas:=TAggLCLCanvas.Create;
  AggLCLCanvas.Image.PixelFormat:=afpimRGBA32;
  AggLCLCanvas.Image.SetSize(2000, 2000);

  {$IFDEF LCLGtk2}
  {HasFont:=true;
  FontFilename:=SetDirSeparators('../../verdana.ttf');
  if not FileExistsUTF8(FontFilename) then begin
    ShowMessage('file not found: '+FontFilename+' CurDir='+GetCurrentDirUTF8);
    HasFont:=false;
  end; }
  // paint to agg canvas
  {with AggLCLCanvas do begin
    if HasFont then begin
      Font.LoadFromFile(FontFilename);
      Font.Size:=10;
      Font.Color:=clBlack;
    end;}
  {$ELSE}
  //HasFont:=false;
  {$ENDIF}

  // solid white background
  AggLCLCanvas.Brush.Color:=clWhite;
  AggLCLCanvas.FillRect(0, 0, AggLCLCanvas.Width, AggLCLCanvas.Height);
end;

procedure TFPVAggPasRenderer.EndRender(var ARenderInfo: TvRenderInfo; ADoDraw: Boolean);
begin
  // convert to LCL native pixel format
  Bitmap.LoadFromIntfImage(AggLCLCanvas.Image.IntfImg);
  TCanvas(ARenderInfo.Canvas).Draw(0, 0, Bitmap);

  AggLCLCanvas.Free;
  Bitmap.Free;
end;

procedure TFPVAggPasRenderer.TPath_Render(var ARenderInfo: TvRenderInfo;
  ADoDraw: Boolean; APath: TPath);
var
  ADest: TFPCustomCanvas absolute ARenderInfo.Canvas;
  ADestX: Integer absolute ARenderInfo.DestX;
  ADestY: Integer absolute ARenderInfo.DestY;
  AMulX: Double absolute ARenderInfo.MulX;
  AMulY: Double absolute ARenderInfo.MulY;
  //
  i, j, curPt: Integer;
  coordX, coordY: Integer;
  curSegment: TPathSegment;
  cur2DSegment: T2DSegment absolute curSegment;
  pts: TPointsArray;
begin
  if not ADoDraw then Exit;

  AggLCLCanvas.Pen.Style := APath.Pen.Style;
  AggLCLCanvas.Pen.Width := APath.Pen.Width;
  AggLCLCanvas.Pen.FPColor := APath.Pen.Color;
  AggLCLCanvas.Brush.Style := APath.Brush.Style;
  AggLCLCanvas.Brush.FPColor := APath.Brush.Color;
  AggLCLCanvas.Brush.AggFillEvenOdd := APath.ClipMode = vcmEvenOddRule;

  AggLCLCanvas.AggResetPath;
  APath.PrepareForSequentialReading;
  for j := 0 to APath.Len - 1 do
  begin
    curSegment := TPathSegment(APath.Next);
    case curSegment.SegmentType of
      stMoveTo:
        begin
          inc(i);
          coordX := CoordToCanvasX(cur2DSegment.X, ADestX, AMulX);
          coordY := CoordToCanvasY(cur2DSegment.Y, ADestY, AMulY);
          AggLCLCanvas.AggMoveTo(coordX, coordY);
        end;
      st2DLineWithPen, st2DLine, st3DLine:
        begin
          coordX := CoordToCanvasX(cur2DSegment.X, ADestX, AMulX);
          coordY := CoordToCanvasY(cur2DSegment.Y, ADestY, AMulY);
          if curSegment.SegmentType = st2DLineWithPen then
          begin
            AggLCLCanvas.Pen.FPColor := APath.AdjustColorToBackground(T2DSegmentWithPen(Cur2DSegment).Pen.Color, ARenderInfo);
            AggLCLCanvas.Pen.Width := T2DSegmentWithPen(cur2DSegment).Pen.Width;
            AggLCLCanvas.Pen.Style := T2DSegmentWithPen(cur2DSegment).Pen.Style;
            AggLCLCanvas.AggLineTo(coordX, coordY);
            AggLCLCanvas.Pen.Style := APath.Pen.Style;
            AggLCLCanvas.Pen.Width := APath.Pen.Width;
            AggLCLCanvas.Pen.FPColor := APath.Pen.Color;
          end
          else
            AggLCLCanvas.AggLineTo(coordX, coordY);
        end;
      st2DBezier, st3DBezier, st2DEllipticalArc:
        begin
          coordX := CoordToCanvasX(T2DSegment(curSegment.Previous).X, ADestX, AMulX);
          coordY := CoordToCanvasY(T2DSegment(curSegment.Previous).Y, ADestY, AMulY);

          SetLength(pts, 1);
          pts[0] := Point(coordX, coordY);
          curSegment.AddToPoints(ADestX, ADestY, AMulX, AMulY, pts);
          for curPt := 0 to Length(pts)-1 do
          begin
            AggLCLCanvas.AggLineTo(pts[curPt].X, pts[curPt].Y);
          end;
          AggLCLCanvas.AggMoveTo(pts[High(pts)].X, pts[High(pts)].Y);
        end;
    end;
  end;
  if APath.Len > 0 then
  begin
    AggLCLCanvas.AggClosePolygon;
    AggLCLCanvas.AggDrawPath(AGG_FillAndStroke, False);
  end;
end;

end.

