{*************************************************}
{ TeeChart Pro XAML (XAML) Canvas and Exporting   }
{ Windows Presentation Foundation Graphics / 3D   }
{ Copyright (c) 2004-2020 by Steema Software      }
{ All Rights Reserved                             }
{*************************************************}
unit TeeXAMLCanvas;
{$I TeeDefs.inc}

interface

uses {$IFNDEF LINUX}
     {$IFNDEF FMX}
     Windows,
     {$ENDIF}
     {$ENDIF}
     Classes,

     {$IFDEF FMX}
     System.UITypes, FMX.Types, FMX.Forms,

     {$IFDEF D17}
     System.UIConsts,
     {$ENDIF}

     {$IFDEF D19}
     FMX.Graphics,
     {$ENDIF}
     
     {$IFDEF D22}
     FMX.Utils,
     {$ENDIF}

     {$ELSE}

     {$IFDEF D16}
     System.UITypes,
     {$ENDIF}

     Graphics, Forms, Controls, StdCtrls,
     {$ENDIF}

     {$IFDEF D6}
     Types,
     {$ENDIF}

     {$IFDEF FMX}
     FMXTee.Canvas, FMXTee.Procs, FMXTee.Engine, FMXTee.Editor.Export
     {$ELSE}
     TeCanvas, TeeProcs, TeEngine, TeeExport
     {$ENDIF};

type
  TXAMLCanvas = class(TTeeNeutralCanvas)
  private
    { Private declarations }
    FX           : TCoordinate;
    FY           : TCoordinate;
    FStrings     : TStrings;

    IGraphicCounter : Integer;
    IPanel       : TCustomTeePanel;

    ISeparator   : Char;

    Procedure Add(Const S:String); {$IFDEF D10}inline;{$ENDIF}
    procedure AddGradient( const APrefix:String;
                           StartColor,MidColor,EndColor:TColor;
                           Direction:TGradientDirection);
    procedure AddGraphic(const AGraphic:TGraphic);
    procedure AddShape(const APrefix,AText:String; UsePen:Boolean=True; UseBrush:Boolean=True);
    Procedure AddStrings(const Strings:String);
    Function PointToStr(const X,Y:TCoordinate):String;
    Function XAMLColor(AColor:TColor):String;
  protected
    { Protected declarations }

    function BeginCanvasTag(ABackColor:TColor):String; virtual;
    function EndCanvasTag:String; virtual;

    function BeginEntity(const Entity:String; const Visual:TVisualBlock=nil; const Transform:TTeeTransform=nil):TVisualBlock; override;
    procedure EndEntity; override;

    { 2d }
    Procedure InternalRect(Const Rect:TRect; UsePen,IsRound:Boolean); virtual;
    procedure SetPixel(X, Y: Integer; Value: TColor); override;

    { 3d }
    procedure SetPixel3D(X,Y,Z:Integer; Value: TColor); override;

    Function XAMLPen:String;
  public
    { Public declarations }
    Constructor CreateText(const Panel:TCustomTeePanel; const AStrings:TStrings); virtual;

    Function InitWindow( const DestCanvas:TCanvas;
                         const A3DOptions:TView3DOptions;
                         ABackColor:TColor;
                         Is3D:Boolean;
                         Const UserRect:TRect):TRect; override;

    procedure Arc(const Left, Top, Right, Bottom, StartX, StartY, EndX, EndY: Integer); override;
    procedure Draw(X, Y: Integer; const Graphic: TGraphic); override;
    procedure FillRect(const Rect: TRect); override;
    procedure Ellipse(const X1, Y1, X2, Y2: TCoordinate); override;
    procedure LineTo(const X,Y:TCoordinate); override;
    procedure MoveTo(const X,Y:TCoordinate); override;
    procedure Pie(X1, Y1, X2, Y2, X3, Y3, X4, Y4: Integer); override;
    procedure Rectangle(const X0,Y0,X1,Y1:TCoordinate); reintroduce; override;
    procedure RoundRect(X1, Y1, X2, Y2, X3, Y3: Integer); override;
    procedure StretchDraw(const Rect: TRect; const Graphic: TGraphic); override;
    Procedure TextOut({$IFDEF FMX}const{$ENDIF} X,Y:TCoordinate; const Text:String); override;

    procedure ClipRectangle(Const Rect:TRect); override;
    procedure UnClipRectangle; override;

    Procedure GradientFill( Const Rect:TRect;
                            StartColor,EndColor:TColor;
                            Direction:TGradientDirection;
                            Balance:Integer=50;
                            RadialX:Integer=0;
                            RadialY:Integer=0); override;

    procedure RotateLabel(x,y:Integer; Const St:String; RotDegree:Double;
                          AllowHTML:Boolean=False); override;
    procedure RotateLabel3D(x,y,z:Integer;
                            const St:String; RotDegree:Double;
                            AllowHTML:Boolean=False); override;
    Procedure Polygon({$IFDEF D6}const{$ENDIF} Points:Array of TPoint); override;
    Procedure Polyline({$IFDEF D6}const{$ENDIF} Points:Array of TPoint); override;

    { 3d }
    procedure EllipseWithZ(const X1, Y1, X2, Y2:TCoordinate; const Z:Integer); override;
    Procedure ShowImage(const DestCanvas,DefaultCanvas:TCanvas; Const UserRect:TRect); override;
    Procedure TextOut3D(X,Y,Z:Integer; const Text:String; AllowHTML:Boolean=False); override;
  end;

  TTextOutItem=packed record
                 XPos,
                 YPos,
                 ZPos     : Integer;
                 FontFamily,
                 ItemText : String;
                 FontColor,
                 ItemBack : TColor;
               end;

  TXAML3DCanvas=class(TXAMLCanvas)
  private
    FZ     : TCoordinate;

    IItems : TStrings;
    ITexts : Array of TTextOutItem;

    procedure AddTransform(const ScaleX,ScaleY,ScaleZ,
                                 TranslateX,TranslateY,TranslateZ,
                                 RotateAngle:Single);

    function GetOpacity:String;
    function IDTag(const Prefix:String):String;
    function TextOutList:String;
  protected
    function BeginCanvasTag(ABackColor:TColor):String; override;
    function BeginEntity(const Entity:String; const Visual:TVisualBlock=nil; const Transform:TTeeTransform=nil):TVisualBlock; override;
    function EndCanvasTag:String; override;
    procedure EndEntity; override;
    Function GetSupportsFullRotation:Boolean; override;
    Procedure InternalRect(Const Rect:TRect; UsePen,IsRound:Boolean); override;
  public
    ScrollBars : Boolean;

    Constructor CreateText(const Panel:TCustomTeePanel; const AStrings:TStrings); override;
    Destructor Destroy; override;

    procedure Cone( Vertical:Boolean; Left,Top,Right,Bottom,Z0,Z1:Integer;
                    Dark3D:Boolean; ConePercent:Integer); override;
    Procedure Cube(Left,Right,Top,Bottom,Z0,Z1:Integer; DarkSides:Boolean=True;
                   RoundSize:Integer=0); override;
    procedure EraseBackground(const Rect: TRect); override;
    procedure LineTo(const X, Y: TCoordinate); override;
    procedure LineTo3D(const X,Y,Z:TCoordinate); override;
    procedure MoveTo3D(const X,Y,Z:TCoordinate); override;
    Procedure Polygon({$IFDEF D6}const{$ENDIF} Points: Array of TPoint); override;
    Procedure RectangleWithZ(Const Rect:TRect; Z:Integer); override;
    Procedure TextOut3D(X,Y,Z:Integer; const Text:String; AllowHTML:Boolean=False); override;
  end;

  TXAMLExportFormat=class(TTeeExportFormat)
  private
    FProperties: TForm;
    Procedure CheckProperties;
  protected
    Procedure DoCopyToClipboard; override;
  public
    Is3D       : Boolean;
    ScrollBars : Boolean;

    function Description:String; override;
    function FileExtension:String; override;
    class function FileFilter:String; override;
    Function XAML:TStringList;

    {$IFDEF FMX}
    function Editor(AOwner:TComponent):TForm; override;
    {$ELSE}
    Function Options(Check:Boolean=True):TForm; override;
    {$ENDIF}

    Procedure SaveToStream(Stream:TStream); override;
  end;

procedure TeeSaveToXAMLFile( const APanel:TCustomTeePanel; const FileName: {$IFDEF D18}String{$ELSE}WideString{$ENDIF};
                             AWidth:Integer=0; AHeight: Integer=0;
                             XAML3D:Boolean=False);

implementation

uses {$IFDEF FMX}
     FMX.Platform,
     {$ELSE}
     Clipbrd,
     {$ENDIF}

     {$IFDEF D16}
     System.IOUtils,
     {$ENDIF}
     
     {$IFDEF FMX}
     FMXTee.Constants,
     {$ELSE}
     TeeConst,
     {$IFNDEF D6}
     TeeHTML,
     {$ENDIF}
     {$ENDIF}
     SysUtils;

{$IFDEF D15}
{$DEFINE TEEFORMAT}
{$ENDIF}

{$IFDEF LCL}
{$DEFINE TEEFORMAT}
{$ENDIF}

Const
  CRLF=TeeTextLineSeparator;

{ TXAMLCanvas }

Constructor TXAMLCanvas.CreateText(const Panel:TCustomTeePanel; const AStrings:TStrings);
begin
  Create;

  IPanel:=Panel;
  FStrings:=AStrings;
  FSupportsAlpha:=True;
  UseBuffer:=False;
end;

Procedure TXAMLCanvas.AddStrings(const Strings:String);
var tmp : String;
    i   : Integer;
begin
  tmp:=Strings;

  repeat
    i:=Pos(CRLF,tmp);

    if i=0 then
    begin
      Add(tmp);
      tmp:='';
    end
    else
    begin
      Add(Copy(tmp,1,i-1));
      Delete(tmp,1,i+1);
    end;
  until tmp='';
end;

Procedure TXAMLCanvas.ShowImage(const DestCanvas,DefaultCanvas:TCanvas; Const UserRect:TRect);
begin
  AddStrings(EndCanvasTag);
  Pen.OnChange:=nil;

  {$IFDEF TEEFORMAT}FormatSettings.{$ENDIF}DecimalSeparator:=ISeparator;
end;

function TXAMLCanvas.EndCanvasTag:String;
begin
  result:='</Canvas>';
end;

function TXAMLCanvas.BeginEntity(const Entity:String; const Visual:TVisualBlock=nil; const Transform:TTeeTransform=nil):TVisualBlock;
begin
  result:=Visual;
end;

procedure TXAMLCanvas.EndEntity;
begin
end;

Procedure TXAMLCanvas.Add(Const S:String);
begin
  FStrings.Add(S);
end;

Function ColorInternal(AColor:TColor):String;
var tmp : Byte;
begin
  //AColor:=ColorToRGB(AColor);

  case AColor of
  {$IFDEF FMX}claBlack{$ELSE}clBlack{$ENDIF}: result:='Black';
  {$IFDEF FMX}claWhite{$ELSE}clWhite{$ENDIF}: result:='White';
  {$IFDEF FMX}claRed{$ELSE}clRed{$ENDIF}:   result:='Red';
  {$IFDEF FMX}claGreen{$ELSE}clGreen{$ENDIF}: result:='Green';
  {$IFDEF FMX}claBlue{$ELSE}clBlue{$ENDIF}:  result:='Blue';
  {$IFDEF FMX}claYellow{$ELSE}clYellow{$ENDIF}: result:='Yellow';
  {$IFDEF FMX}claGray{$ELSE}clGray{$ENDIF}:  result:='Gray';
  {$IFDEF FMX}claNavy{$ELSE}clNavy{$ENDIF}:  result:='Navy';
  {$IFDEF FMX}claOlive{$ELSE}clOlive{$ENDIF}: result:='Olive';
  {$IFDEF FMX}claLime{$ELSE}clLime{$ENDIF}:  result:='Lime';
  {$IFDEF FMX}claTeal{$ELSE}clTeal{$ENDIF}:  result:='Teal';
  {$IFDEF FMX}claSilver{$ELSE}clSilver{$ENDIF}:  result:='Silver';
  {$IFDEF FMX}claPurple{$ELSE}clPurple{$ENDIF}:  result:='Purple';
  {$IFDEF FMX}claFuchsia{$ELSE}clFuchsia{$ENDIF}:  result:='Fuchsia';
  {$IFDEF FMX}claMaroon{$ELSE}clMaroon{$ENDIF}:  result:='Maroon';
  else
  begin
    result:='#';

    tmp:=TTeeCanvas.ColorAlpha(AColor);

    if tmp<>0 then
       result:=result+IntToHex(tmp,2);

    result:=result+IntToHex(TRGBA(AColor).Red,2)+
                   IntToHex(TRGBA(AColor).Green,2)+
                   IntToHex(TRGBA(AColor).Blue,2);
  end;
  end;
end;

Function TXAMLCanvas.XAMLColor(AColor:TColor):String;
begin
  if ITransp<>1 then
  begin
    result:='"#'+IntToHex(255-Round(255*ITransp),2)+
                IntToHex(TRGBA(AColor).Red,2)+
                IntToHex(TRGBA(AColor).Green,2)+
                IntToHex(TRGBA(AColor).Blue,2)+'"';
  end
  else
     result:='"'+ColorInternal(AColor)+'"';
end;

procedure TXAMLCanvas.Rectangle(const X0,Y0,X1,Y1:TCoordinate);
begin
  InternalRect(TeeRect(X0,Y0,X1,Y1),True,False);
end;

procedure TXAMLCanvas.MoveTo(const X, Y: TCoordinate);
begin
  FX:=X;
  FY:=Y;
end;

function ToStr(const Value:TCoordinate):String; {$IFDEF D9}inline;{$ENDIF}
begin
  {$IFDEF FMX}
  result:=FormatFloat('0.###',Value,USFormatSettings);
  {$ELSE}
  result:=TeeStr(Value);
  {$ENDIF}
end;

Function TXAMLCanvas.XAMLPen:String;

  Function PenStyle:String;
  begin
    if Pen.SmallDots then
       result:='Dot'
    else
    Case Pen.Style of
      psSolid: ;
      psDash: result:='Dash';
      psDot: result:='Dot';
      psDashDot: result:='DashDot';
      psDashDotDot: result:='DashDotDot';
    end;
  end;

  function PenWidth:String;
  begin
    if (Pen.Style<>psSolid) and (Pen.Width=1) then
       result:=' StrokeThickness="2" '
    else
    if Pen.Width>1 then
       result:=' StrokeThickness="'+ToStr(Pen.Width)+'" '
    else
       result:='';
  end;

begin
  result:=PenWidth+'Stroke='+XAMLColor(Pen.Color);  // Pen.Style

  if Pen.Style<>psSolid then
     result:=result+' StrokeDashArray="{Binding Source={x:Static DashStyles.'+PenStyle+'}, Path=Dashes}" StrokeDashCap="Round"';
end;

procedure TXAMLCanvas.LineTo(const X, Y: TCoordinate);
begin
  Add('<Line X1="'+ToStr(FX)+'" X2="'+ToStr(X)+
          '" Y1="'+ToStr(FY)+'" Y2="'+ToStr(Y)+'" '+XAMLPen+'/>');

  FX:=X;
  FY:=Y;
end;

procedure TXAMLCanvas.ClipRectangle(Const Rect:TRect);
begin
end;

procedure TXAMLCanvas.UnClipRectangle;
begin
end;

function AddRectangle(Rect:TRect):String;
begin
  Rect:=OrientRectangle(Rect);

  result:=' Canvas.Left="'+ToStr(Rect.Left)+
          '" Canvas.Top="'+ToStr(Rect.Top)+
          '" Width="'+ToStr(Rect.Right-Rect.Left+1)+
          '" Height="'+ToStr(Rect.Bottom-Rect.Top+1)+'"';
end;

procedure TXAMLCanvas.AddGraphic(const AGraphic:TGraphic);
var tmp : String;
begin
  tmp:='Graphic'+IntToStr(IGraphicCounter)+'.'+
       {$IFDEF FMX}'jpg'{$ELSE}GraphicExtension(TGraphicClass(AGraphic.ClassType)){$ENDIF};

  {$IFDEF D16}
  tmp:=TPath.GetTempPath+'\'+tmp;
  {$ENDIF}

  AGraphic.SaveToFile(tmp);
  Add(' <Rectangle.Fill>');
  Add('  <ImageBrush ImageSource="'+tmp+'"/>');
  Add(' </Rectangle.Fill>');
end;

procedure TXAMLCanvas.StretchDraw(const Rect: TRect; const Graphic: TGraphic);
begin
  Add('<Rectangle');
  Add(AddRectangle(Rect)+'>');
  AddGraphic(Graphic);
  Add('</Rectangle>');
end;

procedure TXAMLCanvas.Draw(X, Y: Integer; const Graphic: TGraphic);
begin
  Add('<Rectangle');
  Add(AddRectangle(TeeRect(X,Y,X+Graphic.Width,Y+Graphic.Height))+'>');
  AddGraphic(Graphic);
  Add('</Rectangle>');
end;

Function TXAMLCanvas.PointToStr(const X,Y:TCoordinate):String;
begin
  result:=ToStr(X)+','+ToStr(Y);
end;

procedure TXAMLCanvas.AddGradient( const APrefix:String;
                                   StartColor,MidColor,EndColor:TColor;
                                   Direction:TGradientDirection);

  function StartEndPoints:String;
  begin
    Case Direction of
       gdTopBottom  : result:=' StartPoint="0.5,1" EndPoint="0.5,0"';
       gdBottomTop  : result:=' StartPoint="0.5,0" EndPoint="0.5,1"';
       gdLeftRight  : result:=' StartPoint="1,0.5" EndPoint="0,0.5"';
       gdRightLeft  : result:=' StartPoint="0,0.5" EndPoint="1,0.5"';
       gdFromCenter : result:='';
       gdFromTopLeft: result:='';
    else
       result:='';
    end;
  end;

var tmp : String;
begin
  Add(' <'+APrefix+'.Fill>');

  if Direction=gdRadial then
     tmp:='RadialGradientBrush'
  else
     tmp:='LinearGradientBrush';

  Add('   <'+tmp+StartEndPoints+'>');
  Add('    <GradientStop Offset="0" Color='+XAMLColor(StartColor)+'/>');

  if MidColor=clNone then
     Add('    <GradientStop Offset="1" Color='+XAMLColor(EndColor)+'/>')
  else
  begin
    Add('    <GradientStop Offset="0.5" Color='+XAMLColor(MidColor)+'/>');
    Add('    <GradientStop Offset="1" Color='+XAMLColor(EndColor)+'/>');
  end;

  Add('  </'+tmp+'>');

  Add(' </'+APrefix+'.Fill>');
end;

Procedure TXAMLCanvas.GradientFill( Const Rect:TRect;
                                    StartColor,EndColor:TColor;
                                    Direction:TGradientDirection;
                                    Balance:Integer=50;
                                    RadialX:Integer=0;
                                    RadialY:Integer=0);

begin
  Add('<Rectangle'+AddRectangle(Rect)+'>');
  AddGradient('Rectangle',StartColor,clNone,EndColor,Direction);

//  if ITransp<>0 then
//       Add(' opacity="'+FloatToStr((100-ITransp)*0.01)+'"');

  Add('</Rectangle>');
end;

procedure TXAMLCanvas.FillRect(const Rect: TRect);
begin
  InternalRect(Rect,False,False);
end;

Procedure TXAMLCanvas.InternalRect(Const Rect:TRect; UsePen,IsRound:Boolean);
var tmp  : String;
begin
  if (Brush.Style<>bsClear) or (UsePen and (Pen.Style<>psClear)) then
  begin
    tmp:='';

    if IsRound then
       tmp:=tmp+' RadiusX="30" RadiusY="30"';

    tmp:=tmp+AddRectangle(Rect);

    (*
    if ITransp<>0 then
       tmp:=tmp+' opacity="'+FloatToStr((100-ITransp)*0.01)+'"';
    *)

    AddShape('Rectangle',tmp,UsePen);
  end;
end;

procedure TXAMLCanvas.Ellipse(const X1, Y1, X2, Y2: TCoordinate);
begin
  EllipseWithZ(X1,Y1,X2,Y2,0);
end;

procedure TXAMLCanvas.EllipseWithZ(const X1, Y1, X2, Y2:TCoordinate; const Z: Integer);
var P1, P2 : TPoint;
begin
  if (Brush.Style<>bsClear) or (Pen.Style<>psClear) then
  begin
    Calc3DPoint(P1,X1,Y1,Z);
    Calc3DPoint(P2,X2,Y2,Z);

    AddShape('Ellipse',' Canvas.Left="'+ToStr(P1.X)+
        '" Canvas.Top="'+ToStr(P1.Y)+
        '" Height="'+ToStr(P2.Y-P1.Y+1)+
        '" Width="'+ToStr(P2.X-P1.X+1)+'"');
  end;
end;

procedure TXAMLCanvas.SetPixel3D(X,Y,Z:Integer; Value: TColor);
begin
  if Pen.Style<>psClear then
  begin
    Calc3DPos(x,y,z);
    Pen.Color:=Value;
    MoveTo(x,y);
    LineTo(x,y);
  end;
end;

procedure TXAMLCanvas.SetPixel(X, Y: Integer; Value: TColor);
begin
  if Pen.Style<>psClear then
  begin
    Pen.Color:=Value;
    MoveTo(x,y);
    LineTo(x,y);
  end;
end;

procedure TXAMLCanvas.Arc(const Left, Top, Right, Bottom, StartX, StartY, EndX, EndY: Integer);
var tmpSt : String;
begin
  if Pen.Style<>psClear then
  begin
    tmpSt:=' <v:path v="ar ';
    tmpSt:=tmpSt+PointToStr(Left,Top)+' '+PointToStr(Right,Bottom)+' '+
                 PointToStr(StartX,StartY)+' '+PointToStr(EndX,EndY)+
                 ' e"/>';

    AddShape('Arc',tmpSt);
  end;
end;

procedure TXAMLCanvas.Pie(X1, Y1, X2, Y2, X3, Y3, X4, Y4: Integer);
var tmpSt : String;
begin
  if (Brush.Style<>bsClear) or (Pen.Style<>psClear) then
  begin
    tmpSt:=' <v:path v="m '+PointToStr((X2+X1) div 2,(Y2+Y1) div 2)+' at ';
    tmpSt:=tmpSt+PointToStr(X1,Y1)+' '+PointToStr(X2,Y2)+' '+
                 PointToStr(X3,Y3)+' '+PointToStr(X4,Y4)+
                 ' x e"/>';

    AddShape('Pie',tmpSt);
  end;
end;

procedure TXAMLCanvas.RoundRect(X1, Y1, X2, Y2, X3, Y3: Integer);
begin
  InternalRect(TeeRect(X1,Y1,X2,Y2),True,True);
end;

Procedure TXAMLCanvas.TextOut3D(X,Y,Z:Integer; const Text:String; AllowHTML:Boolean=False);

  Function FontStyle:String;
  begin
    result:='';

    // Style

    if Font.Style<>[] then
    begin
      if {$IFDEF FMX}TFontStyle.{$ENDIF}fsBold in Font.Style then
         result:=result+' FontWeight="Bold"';

      if {$IFDEF FMX}TFontStyle.{$ENDIF}fsItalic in Font.Style then
         result:=result+' FontStyle="Italic"';

      // Not existent in our TeeFont class:
      (*
      if fsOblique in Font.Style then
         result:=result+' FontStyle="Oblique"';
      *)

      // Not existent in XAML
      (*
      if fsUnderline in Font.Style then
         result:=result+' FontStyle="Underline"';

      if fsStrikeOut in Font.Style then
         result:=result+' FontStyle="LineThrough"';
      *)
    end;

    // InterCharSize

    if Font.InterCharSize<>0 then
      if Font.InterCharSize>3 then
         result:=result+' FontStretch="UltraExpanded"'
      else
      if Font.InterCharSize>2 then
         result:=result+' FontStretch="ExtraExpanded"'
      else
      if Font.InterCharSize>1 then
         result:=result+' FontStretch="Expanded"'
      else
      if Font.InterCharSize>0 then
         result:=result+' FontStretch="SemiExpanded"'
      else
      if Font.InterCharSize<-3 then
         result:=result+' FontStretch="UltraCondensed"'
      else
      if Font.InterCharSize<-2 then
         result:=result+' FontStretch="ExtraCondensed"'
      else
      if Font.InterCharSize<-1 then
         result:=result+' FontStretch="Condensed"'
      else
      if Font.InterCharSize<0 then
         result:=result+' FontStretch="SemiCondensed"'
  end;

  Procedure DoText(AX,AY:Integer; AColor:TColor);
  var tmp : String;
      tmpSize : Single;
  begin
    if (TextAlign and TA_CENTER)=TA_CENTER then
       Dec(AX,TextWidth(Text) div 2)
    else
    if (TextAlign and TA_RIGHT)=TA_RIGHT then
       Dec(AX,TextWidth(Text));

    Inc(AX);
    Inc(AY);

    tmpSize:=Font.SizeFloat;

    tmp:='<TextBlock Canvas.Left="'+TeeStr(AX)+
        '" Canvas.Top="'+TeeStr(AY)+
        '" Foreground='+XAMLColor(AColor)+' FontFamily="'+Font.{$IFDEF FMX}Family{$ELSE}Name{$ENDIF}+
        '" FontSize="'+FloatToStr(tmpSize*1.4)+'" '+FontStyle;

    if (BackMode=cbmOpaque) and (BackColor<>clTeeColor) then
       tmp:=tmp+' Background='+XAMLColor(BackColor);

    Add(tmp+'>');

    Add(Text);

    if {$IFDEF FMX}TFontStyle.{$ENDIF}fsUnderline in Font.Style then
    begin
      Add('<TextBlock.TextDecorations>');
      Add('    <TextDecorationCollection>');
      Add('      <TextDecoration');
      Add('        PenThicknessUnit="FontRecommended">');
      Add('        <TextDecoration.Pen>');
      Add('          <Pen Brush='+XAMLColor(Font.Color)+' Thickness="1" />');
      Add('        </TextDecoration.Pen>');
      Add('      </TextDecoration>');
      Add('    </TextDecorationCollection>');
      Add('  </TextBlock.TextDecorations>');
    end;

    Add('</TextBlock>');
  end;

  procedure TryDrawShadow(const AShadow:TTeeShadow; Factor:Integer);
  var tmpX : Integer;
      tmpY : Integer;
  begin
    With AShadow do
    if Visible then
    if (HorizSize<>0) or (VertSize<>0) then
    begin
     if HorizSize<0 then
     begin
       tmpX:=X;
       X:=X-Factor*HorizSize;
     end
     else tmpX:=X+Factor*HorizSize;

     if VertSize<0 then
     begin
       tmpY:=Y;
        Y:=Y-Factor*VertSize;
      end
      else tmpY:=Y+Factor*VertSize;

      DoText(tmpX,tmpY,AShadow.Color)
    end;
  end;

begin
  Calc3DPos(x,y,z);

  TryDrawShadow(Font.Shadow,1);
  TryDrawShadow(Font.Emboss,-1);

  DoText(X,Y,Font.Color);
end;

Procedure TXAMLCanvas.TextOut({$IFDEF FMX}const{$ENDIF} X,Y:TCoordinate; const Text:String);
begin
  TextOut3D({$IFDEF FMX}Round{$ENDIF}(x),
            {$IFDEF FMX}Round{$ENDIF}(y),0,Text);
end;

procedure TXAMLCanvas.RotateLabel3D(x,y,z:Integer; Const St:String; RotDegree:Double;
                                    AllowHTML:Boolean=False);
begin
//TODO: RotDegree rotation
  Calc3DPos(x,y,z);
  TextOut(X,Y,St);
end;

procedure TXAMLCanvas.RotateLabel(x,y:Integer; Const St:String; RotDegree:Double;
                                  AllowHTML:Boolean=False);
begin
  RotateLabel3D(x,y,0,St,RotDegree,AllowHTML);
end;

procedure TXAMLCanvas.AddShape(const APrefix,AText:String; UsePen:Boolean=True; UseBrush:Boolean=True);
var tmp : String;
begin
  if UseBrush and Gradient.Visible then
  begin
    tmp:=AText;

    if UsePen and (Pen.Style<>psClear) then
       tmp:=tmp+' '+XAMLPen;

    Add('<'+APrefix+' '+tmp+'>');

    with Gradient do
         AddGradient(APrefix,StartColor,MidColor,EndColor,Direction);

    Add('</'+APrefix+'>');
  end
  else
  begin
    tmp:='<'+APrefix+' '+AText;

    if UseBrush and (Brush.Style<>bsClear) then
       tmp:=tmp+' Fill='+XAMLColor(Brush.Color);

    if UsePen and (Pen.Style<>psClear) then
       tmp:=tmp+' '+XAMLPen;

    Add(tmp+'/>');
  end;
end;

Procedure TXAMLCanvas.Polygon({$IFDEF D6}const{$ENDIF} Points: Array of TPoint);
var tmpSt : String;
    t     : Integer;
begin
  if (Brush.Style<>bsClear) or (Pen.Style<>psClear) then
  begin
    tmpSt:=' Points="';

    for t:=Low(Points) to High(Points) do
        tmpSt:=tmpSt+PointToStr(Points[t].X,Points[t].Y)+' ';

    tmpSt:=tmpSt+'"';

    AddShape('Polygon',tmpSt);
  end;
end;

Procedure TXAMLCanvas.Polyline({$IFDEF D6}const{$ENDIF} Points:Array of TPoint);
var tmpSt : String;
    t     : Integer;
begin
  if Pen.Style<>psClear then
  begin
    tmpSt:=' Points="';

    for t:=Low(Points) to High(Points) do
        tmpSt:=tmpSt+PointToStr(Points[t].X,Points[t].Y)+' ';

    tmpSt:=tmpSt+'"';

    AddShape('Polyline',tmpSt,True,False);
  end;
end;

function TXAMLCanvas.InitWindow(const DestCanvas: TCanvas;
  const A3DOptions: TView3DOptions; ABackColor: TColor; Is3D: Boolean;
  const UserRect: TRect): TRect;
begin
  result:=inherited InitWindow(DestCanvas,A3DOptions,ABackColor,Is3D,UserRect);

  IGraphicCounter:=0;
  
  ISeparator:={$IFDEF TEEFORMAT}FormatSettings.{$ENDIF}DecimalSeparator;
  {$IFDEF TEEFORMAT}FormatSettings.{$ENDIF}DecimalSeparator:='.';

  AddStrings(BeginCanvasTag(ABackColor));
end;

function TXAMLCanvas.BeginCanvasTag(ABackColor:TColor):String;
begin
  result:='<Canvas Name="'+
            {$IFNDEF TEEOCX}
            IPanel.Name+
            {$ELSE}
            'Chart'+
            {$ENDIF}
            '" Width="'+ToStr(Bounds.Right-Bounds.Left)+
            '" Height="'+ToStr(Bounds.Bottom-Bounds.Top)+
            '" Background='+XAMLColor(ABackColor)+
            ' ClipToBounds="True"'+
            ' xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"'+
            ' xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"'+
            '>';
end;

{ TXAMLExportFormat }

function TXAMLExportFormat.Description: String;
begin
  result:=TeeMsg_AsXAML;
end;

procedure TXAMLExportFormat.DoCopyToClipboard;
begin
  with XAML do
  try
    TeeCopyClipboard(Text);
  finally
    Free;
  end;
end;

function TXAMLExportFormat.FileExtension: String;
begin
  result:='XAML';
end;

class function TXAMLExportFormat.FileFilter: String;
begin
  result:=TeeMsg_XAMLFilter;
end;

Procedure TXAMLExportFormat.CheckProperties;
begin
  if not Assigned(FProperties) then
     FProperties:=CreateProperties('TXAMLOptions');
end;

{$IFDEF FMX}
function TXAMLExportFormat.Editor(AOwner:TComponent):TForm;
{$ELSE}
Function TXAMLExportFormat.Options(Check:Boolean=True):TForm;
{$ENDIF}
begin
  {$IFNDEF FMX}if Check then{$ENDIF} CheckProperties;
  result:=FProperties;
end;

procedure TXAMLExportFormat.SaveToStream(Stream: TStream);
begin
  with XAML do
  try
    SaveToStream(Stream);
  finally
    Free;
  end;
end;

type
  TTeePanelAccess=class(TCustomTeePanel);

// Returns a panel or chart in VML format into a StringList
function TXAMLExportFormat.XAML: TStringList;
var tmp : TCanvas3D;
begin
  CheckSize;
  result:=TStringList.Create;
  Panel.AutoRepaint:=False;

  try
    tmp:=TTeePanelAccess(Panel).InternalCanvas;
    TTeePanelAccess(Panel).InternalCanvas:=nil;

    CheckProperties;

    if Assigned(FProperties) then
       FProperties.CloseQuery;

    if Is3D then
    begin
      Panel.Canvas:=TXAML3DCanvas.CreateText(Panel, result);
      TXAML3DCanvas(Panel.Canvas).ScrollBars:=ScrollBars;
    end
    else
       Panel.Canvas:=TXAMLCanvas.CreateText(Panel, result);

    if not Assigned(Panel.Parent) then
       Panel.BufferedDisplay:=True;

    try
      Panel.Draw(Panel.Canvas.ReferenceCanvas,TeeRect(Width,Height));

      result.Insert(0,'<!-- Generated by TeeChart Pro Version '+TeeChartVersion+' -->');
    finally
      Panel.Canvas:=tmp;
    end;
  finally
    Panel.AutoRepaint:=True;
  end;
end;

procedure TeeSaveToXAMLFile( const APanel:TCustomTeePanel; const FileName: {$IFDEF D18}String{$ELSE}WideString{$ENDIF};
                             AWidth:Integer=0;
                             AHeight:Integer=0;
                             XAML3D:Boolean=False);
begin { save panel or chart to filename in VML (html) format }
  with TXAMLExportFormat.Create do
  try
    Panel:=APanel;
    Height:=AHeight;
    Width:=AWidth;
    Is3D:=XAML3D;
    SaveToFile(FileName);
  finally
    Free;
  end;
end;

{ TXAML3DCanvas }
Constructor TXAML3DCanvas.CreateText(const Panel:TCustomTeePanel; const AStrings:TStrings);
begin
  inherited;
  SupportsID:=True;
  IItems:=TStringList.Create;
end;

Destructor TXAML3DCanvas.Destroy;
begin
  ITexts:=nil;
  IItems.Free;

  inherited;
end;

function TXAML3DCanvas.BeginCanvasTag(ABackColor:TColor):String;

  function CameraRotation:String;
  begin
    if ScrollBars then
       result:='  <PerspectiveCamera.Transform>'+CRLF+
               '     <Transform3DGroup>'+CRLF+
               '       <Transform3DGroup.Children>'+CRLF+
               '         <RotateTransform3D CenterX="0" CenterY="0" CenterZ="-0.5" >'+CRLF+
               '          <RotateTransform3D.Rotation>'+CRLF+
               '            <AxisAngleRotation3D Axis="1 0 0" Angle="{Binding ElementName=scrollV, Path=Value}" />'+CRLF+
               '          </RotateTransform3D.Rotation>'+CRLF+
               '         </RotateTransform3D>'+CRLF+
               '         <RotateTransform3D CenterX="0" CenterY="0" CenterZ="-0.5" >'+CRLF+
               '          <RotateTransform3D.Rotation>'+CRLF+
               '            <AxisAngleRotation3D Axis="0 1 0" Angle="{Binding ElementName=scrollH, Path=Value}" />'+CRLF+
               '          </RotateTransform3D.Rotation>'+CRLF+
               '         </RotateTransform3D>'+CRLF+
               '       </Transform3DGroup.Children>'+CRLF+
               '     </Transform3DGroup>'+CRLF+
               '  </PerspectiveCamera.Transform>'+CRLF
    else
       result:='';
  end;

begin
  if ScrollBars then
     result:='<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"'+CRLF+
             '  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">'+CRLF+
             '  <DockPanel>'+CRLF+
             '          <ScrollBar Name="scrollV" DockPanel.Dock="Right"'+CRLF+
             '                     Minimum="0" Maximum="360"  Value="'+FloatToStr(360-View3DOptions.ElevationFloat)+'"'+CRLF+
             '                     SmallChange="10" LargeChange="10" />'+CRLF+
             ''+CRLF+
             '          <ScrollBar Name="scrollH" DockPanel.Dock="Bottom" Orientation="Horizontal"'+CRLF+
             '                     Minimum="0" Maximum="360"  Value="'+FloatToStr(View3DOptions.RotationFloat)+'"'+CRLF+
             '                     SmallChange="10" LargeChange="10" />'+CRLF
  else
     result:='';

  result:=result+'<Viewport3D Name="'+
            {$IFNDEF TEEOCX}
            IPanel.Name+
            {$ELSE}
            'Chart'+
            {$ENDIF}
          '" ClipToBounds="True"'+CRLF+

//          ' Width="'+IntToStr(IPanel.Width)+'" Height="'+IntToStr(IPanel.Height)+'"'+
//          ' Canvas.Left="0" Canvas.Top="0"'+CRLF+


//            '" Background='+XAMLColor(ABackColor)+

          'xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"'+CRLF+
          'xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"'+CRLF+
          '>';

  result:=result+
   '   <Viewport3D.Resources>'+CRLF+
   '     <MeshGeometry3D x:Key="box"'+CRLF+
   '       Positions="-50,-50,-50 50,-50,-50 -50,50,-50 50,50,-50 -50,-50,50 50, '+
   '-50,50 -50,50,50 50,50,50 -50,-50,-50 50,-50,-50 50,-50,50 50,-50,50 -50,-50,50 '+
   '-50,-50,-50 50,50,-50 50,-50,50 50,50,-50 -50,50,-50 -50,50,50 '+
   '-50,50,50 50,50,50 50,50,-50 -50,50,-50 -50,-50,50 -50,-50,50 -50,50,-50 "'+CRLF+
   '       TriangleIndices="0 2 3  3 1 0  4 5 7  7 6 4  8 9 10  11 12 13  1 14 7  7 15 1  16 17 18  19 20 21  22 0 23  24 6 25  "'+CRLF+
   '       TextureCoordinates="1,0 0,0 1,1 0,1 0,0 1,0 0,1 1,1 0,0 1,0 1,1 1,1 0,1 0,0 1,0 0,1 0,0 1,0 1,1 1,1 0,1 0,0 0,0 1,1 1,1 0,0 "'+CRLF+
   '       Normals="0,0,-1 0,0,-1 0,0,-1 0,0,-1 0,0,1 0,0,1 0,0,1 0,0,1 0,-1,0 0,-1,0 0,-1,0 0,-1,0 1,0,0 1,0,0 1,0,0 1,0,0 0,1,0 0,1,0 0,1,0 0,1,0 -1,0,0 -1,0,0 -1,0,0 -1,0,0 "'+CRLF+
   '     />'+CRLF+
   '     <MeshGeometry3D x:Key="plane"'+CRLF+
   '       TriangleIndices="0,1,2 3,4,5 "'+CRLF+
   '       Normals="0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 "'+CRLF+
   '       TextureCoordinates="0,0 1,0 1,1 1,1 0,1 0,0 "'+CRLF+
   '       Positions="-50,-50,50 50,-50,50 50,50,50 50,50,50 -50,50,50 -50,-50,50 " />'+CRLF+
   '   </Viewport3D.Resources>'+CRLF+
   ''+CRLF+
   '   <Viewport3D.Camera>'+CRLF+
   '     <PerspectiveCamera Position="'+FloatToStr(IPanel.Width*0.5)+
                    ',0'+{FloatToStr(IPanel.Height*0.5)+}
                    ',-550"'+CRLF+
   '                LookDirection="0, 90, 1000"'+CRLF+
   '                UpDirection="0, 0, 1"'+CRLF+
   '                NearPlaneDistance="0.1"'+CRLF+
   '                FarPlaneDistance="1000"'+CRLF+
   '                FieldOfView="'+FloatToStr(0.5*View3DOptions.Perspective)+'" >'+CRLF+
           CameraRotation+
   '     </PerspectiveCamera>'+CRLF+
   '   </Viewport3D.Camera>'+CRLF+
   '   <ModelVisual3D>'+CRLF+
   '     <ModelVisual3D.Content>'+CRLF+
   '       <Model3DGroup>'+CRLF+
   '        <Model3DGroup x:Name="ViewportLights">'+CRLF+
   '          <AmbientLight Color="#FF202020" />'+CRLF+
   '          <DirectionalLight Color="#FFFFFFFF" Direction="0, 0.6, 0.9" />'+CRLF+
   '        </Model3DGroup>'+CRLF;

end;

function TXAML3DCanvas.TextOutList:String;

  function TextOutItem(Index:Integer):String;

    function Background:String;
    begin
      if ITexts[Index].ItemBack=clNone then
         result:=''
      else
         result:=' Background='+XAMLColor(ITexts[Index].ItemBack);
    end;

  begin
    with ITexts[Index] do
      result:='<Viewport2DVisual3D Geometry="{StaticResource plane}">'+CRLF+
         '<Viewport2DVisual3D.Material>'+CRLF+
         '     <DiffuseMaterial  Viewport2DVisual3D.IsVisualHostMaterial="true" />'+CRLF+
         '        </Viewport2DVisual3D.Material>'+CRLF+
         '        <TextBlock FontFamily="'+FontFamily+'"'+
                  Background+' Foreground='+XAMLColor(FontColor)+

                  //TextAlignment="Center"  <Bold><Italic>...

                  '>'+ItemText+'</TextBlock>'+CRLF+
         ' <Viewport2DVisual3D.Transform>'+CRLF+
         '   <Transform3DGroup>'+CRLF+
         '     <Transform3DGroup.Children>'+CRLF+
         '       <ScaleTransform3D ScaleX="0.1" ScaleY="0.1" ScaleZ="-1" />'+CRLF+
         '       <TranslateTransform3D OffsetX="'+IntToStr(XPos-100)+
               '" OffsetY="'+IntToStr(YPos-100)+'" OffsetZ="'+IntToStr(ZPos-50+1)+'" />'+CRLF+
         '     </Transform3DGroup.Children>'+CRLF+
         '   </Transform3DGroup>'+CRLF+
         ' </Viewport2DVisual3D.Transform>'+CRLF+
         '</Viewport2DVisual3D>'+CRLF;
  end;

var t : Integer;
begin
  result:='';

  for t:=0 to Length(ITexts)-1 do
      result:=result+TextOutItem(t);
end;

function TXAML3DCanvas.EndCanvasTag:String;
begin
  result:='        </Model3DGroup>'+CRLF+
          '     </ModelVisual3D.Content>'+CRLF+
          '   </ModelVisual3D>'+CRLF+

          TextOutList+

          '</Viewport3D>'+CRLF;

  if ScrollBars then
     result:=result+'</DockPanel>'+CRLF+'</Page>'+CRLF;
end;

procedure TXAML3DCanvas.EraseBackground(const Rect: TRect);
begin // empty
end;

Function TXAML3DCanvas.GetSupportsFullRotation:Boolean;
begin
  result:=True;
end;

function TXAML3DCanvas.GetOpacity:String;
begin
  if ITransp=1 then
     result:=''
  else
     result:=' Opacity="'+FormatFloat('0.##',1-ITransp)+'"';
end;

Procedure TXAML3DCanvas.RectangleWithZ(Const Rect:TRect; Z:Integer);
begin
  Cube(Rect,Z,Z+1);
end;

Procedure TXAML3DCanvas.InternalRect(Const Rect:TRect; UsePen,IsRound:Boolean);
begin
  Cube(Rect,0,1);

  (*
  Add('<Model3DGroup x:Name="'+IDTag('plane')+'">');
  Add(' <Model3DGroup.Transform>');
  Add('   <Transform3DGroup>');
  Add('     <Transform3DGroup.Children>');
  Add('       <ScaleTransform3D ScaleX="'+FloatToStr((Rect.Right-Rect.Left)*0.01)+
                             '" ScaleY="'+FloatToStr((Rect.Bottom-Rect.Top)*0.01)+
                             '" ScaleZ="0.01" '+
                             '/>');
  Add('       <TranslateTransform3D OffsetX="'+
                      IntToStr(Rect.Left-(100-(Rect.Right-Rect.Left) div 2))+
                      '" OffsetY="'+IntToStr(Rect.Top-(100-(Rect.Bottom-Rect.Top) div 2))+
                      '" OffsetZ="-50"/>');
  Add('     </Transform3DGroup.Children>');
  Add('   </Transform3DGroup>');
  Add(' </Model3DGroup.Transform>');
  Add(' <GeometryModel3D Geometry="{StaticResource box}">');
  Add('   <GeometryModel3D.Material>');
  Add('     <DiffuseMaterial>');
  Add('        <DiffuseMaterial.Brush>');
  Add('          <SolidColorBrush Color='+XAMLColor(Brush.Color)+GetOpacity+'/>');
  Add('        </DiffuseMaterial.Brush>');
  Add('     </DiffuseMaterial>');
  Add('   </GeometryModel3D.Material>');
  Add(' </GeometryModel3D>');
  Add('</Model3DGroup>');
  *)
end;

// Generates unique ID starting with Prefix and optionally "_xxx" (number)
function TXAML3DCanvas.IDTag(const Prefix:String):String;
var tmp : Integer;
    tmpValue : Integer;
begin
  if Trim(Prefix)='' then
     result:='id'
  else
     result:=Trim(Prefix);

  if TryStrToInt(result,tmpValue) then
     result:='id_'+result;

  tmp:=0;

  while IITems.IndexOf(result)<>-1 do
  begin
    result:=Prefix+'_'+IntToStr(tmp);
    Inc(tmp);
  end;

  IITems.Add(result);
end;

function TXAML3DCanvas.BeginEntity(const Entity:String; const Visual:TVisualBlock=nil; const Transform:TTeeTransform=nil):TVisualBlock;
begin
  result:=Visual;
  Add('<Model3DGroup x:Name="'+IDTag(Entity)+'">');

  if Assigned(Transform) then
  with Transform do
       AddTransform(Scale.x,Scale.y,1,Translate.x,Translate.y,0,Rotate);
end;

procedure TXAML3DCanvas.EndEntity;
begin
  Add('</Model3DGroup>');
end;

procedure TXAML3DCanvas.AddTransform(const ScaleX,ScaleY,ScaleZ,
                                           TranslateX,TranslateY,TranslateZ,
                                           RotateAngle:Single);
begin
  Add(' <Model3DGroup.Transform>');
  Add('   <Transform3DGroup>');
  Add('     <Transform3DGroup.Children>');

  Add('       <ScaleTransform3D ScaleX="'+FloatToStr(ScaleX)+
                             '" ScaleY="'+FloatToStr(ScaleY)+
                             '" ScaleZ="'+FloatToStr(ScaleZ)+'" '+

                             // "CenterX, CenterY, CenterZ"

                             '/>');

  Add('       <TranslateTransform3D OffsetX="'+FloatToStr(TranslateX)+
                      '" OffsetY="'+FloatToStr(TranslateY)+
                      '" OffsetZ="'+FloatToStr(TranslateZ)+'" />');

  if RotateAngle<>0 then
  begin
    Add('       <RotateTransform3D>');
    Add('         <RotateTransform3D.Rotation>');
    Add('           <AxisAngleRotation3D Angle="'+FloatToStr(RotateAngle)+'" />');
    Add('         </RotateTransform3D.Rotation>');
    Add('       </RotateTransform3D>');
  end;

  Add('     </Transform3DGroup.Children>');
  Add('   </Transform3DGroup>');
  Add(' </Model3DGroup.Transform>');
end;

Procedure TXAML3DCanvas.Cube(Left,Right,Top,Bottom,Z0,Z1:Integer;
                             DarkSides:Boolean=True;
                             RoundSize:Integer=0);
begin
  Add('<Model3DGroup x:Name="'+IDTag('cube')+'">');

  AddTransform((Right-Left)*0.01,(Bottom-Top)*0.01,(Z1-Z0)*0.01,
               Left-(100-(Right-Left) div 2),
               Top-(100-(Bottom-Top) div 2),
               Z0-(100-(Z1-Z0) div 2),
               0);

  Add(' <GeometryModel3D Geometry="{StaticResource box}">');
  Add('   <GeometryModel3D.Material>');
  Add('     <DiffuseMaterial>');
  Add('        <DiffuseMaterial.Brush>');
  Add('          <SolidColorBrush Color='+XAMLColor(Brush.Color)+GetOpacity+'/>');
  Add('        </DiffuseMaterial.Brush>');
  Add('     </DiffuseMaterial>');
  Add('   </GeometryModel3D.Material>');
  Add(' </GeometryModel3D>');
  Add('</Model3DGroup>');
end;

procedure TXAML3DCanvas.Cone( Vertical:Boolean; Left,Top,Right,Bottom,Z0,Z1:Integer;
                    Dark3D:Boolean; ConePercent:Integer);
begin
  // Pending
end;

Procedure TXAML3DCanvas.TextOut3D(X,Y,Z:Integer; const Text:String; AllowHTML:Boolean=False);
begin
  // Pending
  // ModelGroup3D + VisualBrush TextBlock... ?  Or Viewport2DVisual3D... ?

  SetLength(ITexts,Length(ITexts)+1);

  with ITexts[Length(ITexts)-1] do
  begin
    XPos:=X;
    YPos:=Y;
    ZPos:=Z;
    ItemText:=Text;
    FontFamily:=Font.{$IFDEF FMX}Family{$ELSE}Name{$ENDIF};

    FontColor:=Font.Color;

    if BackMode=cbmOpaque then
       ItemBack:=BackColor
    else
       ItemBack:=clNone;
  end;
end;

procedure TXAML3DCanvas.LineTo(const X, Y: TCoordinate);
begin
  LineTo3D(X,Y,0);
end;

procedure TXAML3DCanvas.LineTo3D(const X,Y,Z:TCoordinate);
var tmpX,tmpY,tmpZ : TCoordinate;
begin
  tmpX:=X;
  tmpY:=Y;
  tmpZ:=Z;

  if FX=X then tmpX:=tmpX+1;
  if FY=Y then tmpY:=tmpY+1;
  if FZ=Z then tmpZ:=tmpZ+1;

  Cube(TeeRect(FX,FY,tmpX,tmpY),{$IFDEF FMX}Round{$ENDIF}(FZ),
                                {$IFDEF FMX}Round{$ENDIF}(tmpZ));
end;

procedure TXAML3DCanvas.MoveTo3D(const X,Y,Z:TCoordinate);
begin
  FX:=X;
  FY:=Y;
  FZ:=Z;
end;

Procedure TXAML3DCanvas.Polygon({$IFDEF D6}const{$ENDIF} Points: Array of TPoint);
begin
  // Pending
end;

initialization
  {$IFDEF FMX}
  TTeeExportFormats.RegisterFormat(TXAMLExportFormat);
  {$ELSE}
  RegisterTeeExportFormat(TXAMLExportFormat);
  {$ENDIF}
finalization
  {$IFDEF FMX}
  TTeeExportFormats.UnRegisterFormat(TXAMLExportFormat);
  {$ELSE}
  UnRegisterTeeExportFormat(TXAMLExportFormat);
  {$ENDIF}
end.

