ASP源码.NET源码PHP源码JSP源码JAVA源码DELPHI源码PB源码VC源码VB源码Android源码
当前位置:首页 >> 低调看直播体育app软件下载 >> Delphijrs看球网直播吧_低调看直播体育app软件下载_低调看体育直播 >> Spine Runtime for Delphi移植笔记(六) - spinecoreskeletonbinary

Spine Runtime for Delphi移植笔记(六) - spinecoreskeletonbinary

来源:网络整理     时间:2017-08-02     关键词:

本篇文章主要介绍了" Spine Runtime for Delphi移植笔记(六) - spinecoreskeletonbinary",主要涉及到方面的内容,对于Delphijrs看球网直播吧_低调看直播体育app软件下载_低调看体育直播感兴趣的同学可以参考一下: ////////////////////////////////////////////////////////////////////////////////...

////////////////////////////////////////////////////////////////////////////////
//Generic delphi runtime v3.6 for Spine animation tool                        //
//Runtime port by cjk (hzi1980@163.com)                                       //
////////////////////////////////////////////////////////////////////////////////unit spine.core.skeleton.binary;

interfaceuses
  System.Classes, System.SysUtils, System.Generics.Collections, System.Math,
  spine.types, spine.classes, spine.data,
  spine.core.atlas, spine.core.bone, spine.core.slot, spine.core.skin,
  spine.core.attachment, spine.core.constraint, spine.core.skeleton,
  spine.core.animation.timeline, spine.core.skeleton.json, spine.core.event,
  spine.core.animation;

type
  SByte = ShortInt;
  TSpineSkeletonBinary = classpublicconst
        BONE_ROTATE = 0;
        BONE_TRANSLATE = 1;
        BONE_SCALE = 2;
        BONE_SHEAR = 3;

        SLOT_ATTACHMENT = 0;
        SLOT_COLOR = 1;
        SLOT_TWO_COLOR = 2;

        PATH_POSITION = 0;
        PATH_SPACING = 1;
        PATH_MIX = 2;

        CURVE_LINEAR = 0;
        CURVE_STEPPED = 1;
        CURVE_BEZIER = 2;
  privatetype
        TVertices = record
            Bones: TArray;
            Vertices: TArray;
        end;
  private
    FLinkedMeshes: TObjectList;
    FAttachmentLoader: TAttachmentLoader;
    FBuffer: array [0..31] of Byte;
    function ReadByte(const AStream: TStream): Integer;
    function ReadString(const AStream: TStream): string;
    function ReadInt(const AStream: TStream): Integer;
    function ReadFloat(const AStream: TStream): Single;
    function ReadBoolean(const AStream: TStream): Boolean;
    function ReadSByte(const AStream: TStream): SByte;
    function ReadVarInt(const AStream: TStream; const AOptimizePositive: Boolean): Integer;
    function ReadShortArray(const AStream: TStream): TArray;
    function ReadFloatArray(const AStream: TStream; const ACount: Integer;
      const AScale: Single): TArray;
    function ReadVertices(const AStream: TStream; const AVertexCount: Integer): TVertices;
    function ReadAttachment(const AStream: TStream; const ASkeletonData: TSkeletonData;
      const ASkin: TSpineSkin; const ASlotIndex: Integer;
      const AAttachmentName: string; const ANonessential: Boolean): IAttachment;
    function ReadSkin (const AStream: TStream; const ASkeletonData: TSkeletonData;
      const ASkinName: string; const ANonessential: Boolean): TSpineSkin;
    procedure ReadCurve(const AStream: TStream; const AFrameIndex: Integer; const ATimeline: TCurveTimeline);
    procedure ReadAnimation(const AName: string; const AStream: TStream; const ASkeletonData: TSkeletonData);
    classprocedure ReadFully(const AStream: TStream; var ABuffer: TArray;
      const AOffset: Integer; var ALength: Integer); static;
  public
    Scale: Single;
    constructorCreate(const AAtlasArray: TArray); overload;
    constructorCreate(const AAttachmentLoader: TAttachmentLoader); overload;
    destructorDestroy; override;

    function ReadSkeletonData(const ASkelFile: string): TSkeletonData; overload;
    function ReadSkeletonData(const ASkelStream: TStream): TSkeletonData; overload;
  end;

implementation{ TSpineSkeletonBinary }constructor TSpineSkeletonBinary.Create(const AAtlasArray: TArray);
begin
  FAttachmentLoader:= TAtlasAttachmentLoader.Create(AAtlasArray);
  Create(FAttachmentLoader);
end;

constructor TSpineSkeletonBinary.Create(
  const AAttachmentLoader: TAttachmentLoader);
begininheritedCreate;
  ifnot Assigned(AAttachmentLoader) thenraise Exception.Create('attachmentLoader cannot be null.');
  FLinkedMeshes:= TObjectList.Create;
  FAttachmentLoader:= AAttachmentLoader;
end;

destructor TSpineSkeletonBinary.Destroy;
begin
  FLinkedMeshes.Free;
  if Assigned(FAttachmentLoader) thenFreeAndNil(FAttachmentLoader);  
  inherited;
end;

function TSpineSkeletonBinary.ReadSkeletonData(
  const ASkelFile: string): TSkeletonData;
var
  lStream: TFileStream;
begin
  lStream:= TFileStream.Create(ASkelFile, fmOpenRead);
  try
    result:= Self.ReadSkeletonData(lStream);
  finally
    lStream.Free;
  end;
end;

function TSpineSkeletonBinary.ReadSkeletonData(
  const ASkelStream: TStream): TSkeletonData;
var
  lScale: Single;
  lNonessential: Boolean;
  i, j, n, nn: Integer;
  lName: string;
  lBoneDataParent, lBoneData: TBoneData;
  lColor, lDarkColor: Integer;
  lSlotData: TSlotData;
  lIkConstraintData: TIkConstraintData;
  lTransformConstraintData: TTransformConstraintData;
  lPathConstraintData: TPathConstraintData;
  lDefaultSkin, lSkin: TSpineSkin;
  lLinkedMesh: TSkeletonJson.TLinkedMesh;
  lParentAttachment: IAttachment;
  lEventData: TEventData;
beginifnot Assigned(ASkelStream) thenraise Exception.Create('skelstream cannot be null.');
  result:= TSkeletonData.Create;
  result.Name:= ChangeFileExt(ExtractFileName(TFileStream(ASkelStream).FileName),'');
  result.Hash:= Self.ReadString(ASkelStream);
  result.Version:= Self.ReadString(ASkelStream);
  result.Width:= Self.ReadFloat(ASkelStream);
  result.Height:= Self.ReadFloat(ASkelStream);
  lNonessential:= Self.ReadBoolean(ASkelStream);
  if lNonessential thenbegin
    result.FPS:= Self.ReadFloat(ASkelStream);
    result.ImagesPath:= Self.ReadString(ASkelStream);
  end;

  // Bones.
  n:= Self.ReadVarInt(ASkelStream, True);
  for i:= 0to n -1dobegin
    lName:= Self.ReadString(ASkelStream);
    if i = 0then
      lBoneDataParent:= nilelse
      lBoneDataParent:= result.BoneDatas.Items[Self.ReadVarInt(ASkelStream, True)];
    lBoneData:= TBoneData.Create(i, lName, lBoneDataParent);
    lBoneData.Rotation:= Self.ReadFloat(ASkelStream);
    lBoneData.X:= Self.ReadFloat(ASkelStream) * Self.Scale;
    lBoneData.Y:= Self.ReadFloat(ASkelStream) * Self.Scale;
    lBoneData.ScaleX:= Self.ReadFloat(ASkelStream);
    lBoneData.ScaleY:= Self.ReadFloat(ASkelStream);
    lBoneData.ShearX:= Self.ReadFloat(ASkelStream);
    lBoneData.ShearY:= Self.ReadFloat(ASkelStream);
    lBoneData.Length:= Self.ReadFloat(ASkelStream) * Self.Scale;
    //lBoneData.TransformMode:= TTransformModes[Self.ReadVarInt(ASkelStream, True)];if lNonessential then Self.ReadInt(ASkelStream); // Skip bone color.    result.BoneDatas.Add(lBoneData);
  end;

  // Slots.
  n:= Self.ReadVarInt(ASkelStream, True);
  for i:= 0to n -1dobegin
    lName:= Self.ReadString(ASkelStream);
    lBoneData:= result.BoneDatas.Items[Self.ReadVarInt(ASkelStream, True)];
    lSlotData:= TSlotData.Create(i, lName, lBoneData);
    lColor:= Self.ReadInt(ASkelStream);
    lSlotData.R:= ((lColor and $ff) shr24) / 255;
    lSlotData.G:= ((lColor and $00ff) shr16) / 255;
    lSlotData.B:= ((lColor and $0000ff) shr8) / 255;
    lSlotData.A:= (lColor and $000000ff) / 255;
    lDarkColor:= Self.ReadInt(ASkelStream); // 0x00rrggbbif lDarkColor <> -1thenbegin
      lSlotData.HasSecondColor:= True;
      lSlotData.R2:= ((lDarkColor and $00ff) shr16) / 255;
      lSlotData.G2:= ((lDarkColor and $0000ff) shr8) / 255;
      lSlotData.B2:= (lDarkColor and $000000ff) / 255;
    end;
    lSlotData.AttachmentName:= Self.ReadString(ASkelStream);
    lSlotData.BlendMode:= TBlendMode(Self.ReadVarInt(ASkelStream, True));
    result.SlotDatas.Add(lSlotData);
  end;

  // IK constraints.
  n:= Self.ReadVarInt(ASkelStream, True);
  for i:= 0to n -1dobegin
    lIkConstraintData:= TIkConstraintData.Create(Self.ReadString(ASkelStream));
    lIkConstraintData.Order:= Self.ReadVarInt(ASkelStream, True);
    nn:= Self.ReadVarInt(ASkelStream, True);
    for j:= 0to nn -1do
      lIkConstraintData.BoneDatas.Add(result.BoneDatas.Items[Self.ReadVarInt(ASkelStream, True)]);
    lIkConstraintData.Target:= result.BoneDatas.Items[Self.ReadVarInt(ASkelStream, True)];
    lIkConstraintData.Mix:= Self.ReadFloat(ASkelStream);
    lIkConstraintData.BendDirection:= Self.ReadSByte(ASkelStream);
    result.IkConstraintDatas.Add(lIkConstraintData);
  end;

  // Transform constraints.
  n:= Self.ReadVarInt(ASkelStream, True);
  for i:= 0to n -1dobegin
    lTransformConstraintData:= TTransformConstraintData.Create(Self.ReadString(ASkelStream));
    lTransformConstraintData.Order:= Self.ReadVarInt(ASkelStream, True);
    nn:= Self.ReadVarInt(ASkelStream, True);
    for j:= 0to nn -1do
      lTransformConstraintData.BoneDatas.Add(result.BoneDatas.Items[Self.ReadVarInt(ASkelStream, True)]);
    lTransformConstraintData.Target:= result.BoneDatas.Items[Self.ReadVarInt(ASkelStream, True)];
    lTransformConstraintData.Local:= Self.ReadBoolean(ASkelStream);
    lTransformConstraintData.Relative:= Self.ReadBoolean(ASkelStream);
    lTransformConstraintData.OffsetRotation:= Self.ReadFloat(ASkelStream);
    lTransformConstraintData.OffsetX:= Self.ReadFloat(ASkelStream) * Self.Scale;
    lTransformConstraintData.OffsetY:= Self.ReadFloat(ASkelStream) * Self.Scale;
    lTransformConstraintData.OffsetScaleX:= Self.ReadFloat(ASkelStream);
    lTransformConstraintData.OffsetScaleY:= Self.ReadFloat(ASkelStream);
    lTransformConstraintData.OffsetShearY:= Self.ReadFloat(ASkelStream);
    lTransformConstraintData.RotateMix:= Self.ReadFloat(ASkelStream);
    lTransformConstraintData.TranslateMix:= Self.ReadFloat(ASkelStream);
    lTransformConstraintData.ScaleMix:= Self.ReadFloat(ASkelStream);
    lTransformConstraintData.ShearMix:= Self.ReadFloat(ASkelStream);
    result.TransformConstraintDatas.Add(lTransformConstraintData);
  end;

  // Path constraints
  n:= Self.ReadVarInt(ASkelStream, True);
  for i:= 0to n -1dobegin
    lPathConstraintData:= TPathConstraintData.Create(Self.ReadString(ASkelStream));
    lPathConstraintData.Order:= Self.ReadVarInt(ASkelStream, True);
    nn:= Self.ReadVarInt(ASkelStream, True);
    for j:= 0to nn -1do
      lPathConstraintData.BoneDatas.Add(result.BoneDatas.Items[Self.ReadVarInt(ASkelStream, True)]);
    lPathConstraintData.Target:= result.SlotDatas.Items[Self.ReadVarint(ASkelStream, true)];
    lPathConstraintData.PositionMode:= TPositionMode(Self.ReadVarint(ASkelStream, true));
    lPathConstraintData.SpacingMode:= TSpacingMode(Self.ReadVarint(ASkelStream, true));
    lPathConstraintData.RotateMode:= TRotateMode(Self.ReadVarint(ASkelStream, true));
    lPathConstraintData.OffsetRotation:= Self.ReadFloat(ASkelStream);
    lPathConstraintData.Position:= Self.ReadFloat(ASkelStream);
    if lPathConstraintData.PositionMode = TPositionMode.pmFixed then
      lPathConstraintData.Position:= lPathConstraintData.Position * Self.Scale;
    lPathConstraintData.Spacing:= Self.ReadFloat(ASkelStream);
    if (lPathConstraintData.SpacingMode = TSpacingMode.smLength) or
       (lPathConstraintData.SpacingMode = TSpacingMode.smFixed) then
      lPathConstraintData.Spacing:= lPathConstraintData.Spacing * Self.Scale;
    lPathConstraintData.RotateMix:= Self.ReadFloat(ASkelStream);
    lPathConstraintData.TranslateMix:= Self.ReadFloat(ASkelStream);
    result.PathConstraintDatas.Add(lPathConstraintData);
  end;

  // Default skin.
  lDefaultSkin:= Self.ReadSkin(ASkelStream, result, 'default', lNonessential);
  if Assigned(lDefaultSkin) thenbegin
    result.DefaultSkin:= lDefaultSkin;
    result.Skins.Add(lDefaultSkin);
  end;

  // Skins.
  n:= Self.ReadVarInt(ASkelStream, True);
  for i:= 0to n -1do
    result.Skins.Add(Self.ReadSkin(ASkelStream, result, Self.ReadString(ASkelStream), lNonessential));

  // Linked meshes.
  n:= FLinkedMeshes.Count;
  for i:= 0to n -1dobegin
    lLinkedMesh:= FLinkedMeshes[i];
    ifnot Assigned(lLinkedMesh) then
      lSkin:= lDefaultSkin
    else
      lSkin:= result.FindSkin(lLinkedMesh.Skin);
    ifnot Assigned(lSkin) thenraise Exception.CreateFmt('Skin not found: %s',[lLinkedMesh.Skin]);
    lParentAttachment:= lSkin.GetAttachment(lLinkedMesh.SlotIndex, lLinkedMesh.Parent);
    ifnot Assigned(lParentAttachment) thenraise Exception.CreateFmt('Parent mesh not found: %s',[lLinkedMesh.Parent]);
    lLinkedMesh.Mesh.ParentMesh:= TMeshAttachment(lParentAttachment);
    lLinkedMesh.Mesh.UpdateUVs;
  end;
  FLinkedMeshes.Clear;

  // Events.
  n:= Self.ReadVarInt(ASkelStream, True);
  for i:= 0to n -1dobegin
    lEventData:= TEventData.Create(Self.ReadString(ASkelStream));
    lEventData.IntValue:= Self.ReadVarInt(ASkelStream, False);
    lEventData.FloatValue:= Self.ReadFloat(ASkelStream);
    lEventData.StringValue:= Self.ReadString(ASkelStream);
    result.EventDatas.Add(lEventData);
  end;

  // Animations.
  n:= Self.ReadVarInt(ASkelStream, True);
  for i:= 0to n -1do
    Self.ReadAnimation(Self.ReadString(ASkelStream), ASkelStream, result);

  result.BoneDatas.TrimExcess;
  result.SlotDatas.TrimExcess;
  result.Skins.TrimExcess;
  result.EventDatas.TrimExcess;
  result.Animations.TrimExcess;
  result.IkConstraintDatas.TrimExcess;
  result.TransformConstraintDatas.TrimExcess;
  result.PathConstraintDatas.TrimExcess;
end;

function TSpineSkeletonBinary.ReadByte(const AStream: TStream): Integer;
beginif AStream.Position + 1 > AStream.Size then exit(-1);
  AStream.Read(result, 1);
end;

function TSpineSkeletonBinary.ReadSkin(const AStream: TStream;
  const ASkeletonData: TSkeletonData; const ASkinName: string;
  const ANonessential: Boolean): TSpineSkin;
var
  lSlotCount, i, lSlotIndex, j, n: Integer;
  lName: string;
  lAttachment: IAttachment;
begin
  lSlotCount:= Self.ReadVarInt(AStream, True);
  if lSlotCount = 0then exit(nil);
  result:= TSpineSkin.Create;
  for i:= 0to lSlotCount -1dobegin
    lSlotIndex:= Self.ReadVarInt(AStream, True);
    n:= Self.ReadVarInt(AStream, True);
    for j:= 0to n -1dobegin
      lName:= Self.ReadString(AStream);
      lAttachment:= Self.ReadAttachment(AStream, ASkeletonData, result, lSlotIndex, lName, ANonessential);
      if Assigned(lAttachment) then
        result.AddAttachment(lSlotIndex, lName, lAttachment);
    end;
  end;
end;

function TSpineSkeletonBinary.ReadAttachment(const AStream: TStream;
  const ASkeletonData: TSkeletonData; const ASkin: TSpineSkin;
  const ASlotIndex: Integer; const AAttachmentName: string;
  const ANonessential: Boolean): IAttachment;
var
  lName, lPath: string;
  lAttachmentType: TAttachmentType;
  lRotation, lX, lY, lScaleX, lScaleY, lWidth, lHeight: Single;
  lColor: Integer;
  lRegionAttachment: TRegionAttachment;
  lVertexCount: Integer;
  lVertices: TVertices;
  lBoxAttachment: TBoundingBoxAttachment;
  lUVs: TArray;
  lTriangles, lEdges: TArray;
  lHullLength: Integer;
  lMeshAttachment: TMeshAttachment;
  lSkinName, lParentMeshName: string;
  lInheritDeform: Boolean;
  lClosed, lConstantSpeed: Boolean;
  lLengths: TArray;
  i: Integer;
  lPathAttachment: TPathAttachment;
  lPointAttachment: TPointAttachment;
  lEndSlotIndex: Integer;
  lClippingAttachment: TClippingAttachment;
begin
  lName:= Self.ReadString(AStream);
  if lName.Trim.IsEmpty then lName:= AAttachmentName;
  lAttachmentType:= TAttachmentType(Self.ReadByte(AStream));
  case lAttachmentType of
    TAttachmentType.atRegion:
      begin
        lPath:= Self.ReadString(AStream);
        lRotation:= Self.ReadFloat(AStream);
        lX:= Self.ReadFloat(AStream);
        lY:= Self.ReadFloat(AStream);
        lScaleX:= Self.ReadFloat(AStream);
        lScaleY:= Self.ReadFloat(AStream);
        lWidth:= Self.ReadFloat(AStream);
        lHeight:= Self.ReadFloat(AStream);
        lColor:= Self.ReadInt(AStream);
        if lPath.Trim.IsEmpty then lPath:= lName;
        //
        lRegionAttachment:= FAttachmentLoader.NewRegionAttachment(ASkin, lName, lPath);
        ifnot Assigned(lRegionAttachment) then exit(nil);
        lRegionAttachment.Path:= lPath;
        lRegionAttachment.X:= lX * Self.Scale;
        lRegionAttachment.Y:= lY * Self.Scale;
        lRegionAttachment.ScaleX:= lScaleX;
        lRegionAttachment.ScaleY:= lScaleY;
        lRegionAttachment.Rotation:= lRotation;
        lRegionAttachment.Width:= lWidth * Self.Scale;
        lRegionAttachment.Height:= lHeight * Self.Scale;
        lRegionAttachment.R:= ((lColor and $ff) shr24) / 255;
        lRegionAttachment.G:= ((lColor and $00ff) shr16) / 255;
        lRegionAttachment.B:= ((lColor and $0000ff) shr8) / 255;
        lRegionAttachment.A:= ((lColor and $000000ff)) / 255;
        lRegionAttachment.UpdateOffset();
        exit(lRegionAttachment);
      end;
    TAttachmentType.atBoundingbox:
      begin
        lVertexCount:= Self.ReadVarint(AStream, True);
        lVertices:= Self.ReadVertices(AStream, lVertexCount);
        if ANonessential then Self.ReadInt(AStream);
        //
        lBoxAttachment:= FAttachmentLoader.NewBoundingBoxAttachment(ASkin, lName);
        ifnot Assigned(lBoxAttachment) then exit(nil);
        lBoxAttachment.WorldVerticesLength:= lVertexCount shl1;
        SetLength(lBoxAttachment.Vertices, Length(lVertices.Vertices));
        SetLength(lBoxAttachment.Bones, Length(lVertices.Bones));
        TArray.Copy(lVertices.Vertices, lBoxAttachment.Vertices, 0, 0, Length(lVertices.Vertices));
        TArray.Copy(lVertices.Bones, lBoxAttachment.Bones, 0, 0, Length(lVertices.Bones));
        exit(lBoxAttachment);
      end;
    TAttachmentType.atMesh:
      begin
        lPath:= Self.ReadString(AStream);
        lColor:= Self.ReadInt(AStream);
        lVertexCount:= Self.ReadVarInt(AStream, True);
        lUVs:= Self.ReadFloatArray(AStream, lVertexCount shl1, 1);
        lTriangles:= Self.ReadShortArray(AStream);
        lVertices:= Self.ReadVertices(AStream, lVertexCount);
        lHullLength:= Self.ReadVarInt(AStream, True);
        lWidth:= 0;
        lHeight:= 0;
        if ANonessential thenbegin
          lEdges:= Self.ReadShortArray(AStream);
          lWidth:= Self.ReadFloat(AStream);
          lHeight:= Self.ReadFloat(AStream);
        end;
        if lPath.Trim.IsEmpty then lPath:= lName;
        lMeshAttachment:= FAttachmentLoader.NewMeshAttachment(ASkin, lName, lPath);
        ifnot Assigned(lMeshAttachment) then exit(nil);
        lMeshAttachment.Path:= lPath;
        lMeshAttachment.R:= ((lColor and $ff) shr24) / 255;
        lMeshAttachment.G:= ((lColor and $00ff) shr16) / 255;
        lMeshAttachment.B:= ((lColor and $0000ff) shr8) / 255;
        lMeshAttachment.A:= ((lColor and $000000ff)) / 255;
        SetLength(lMeshAttachment.Vertices, Length(lVertices.Vertices));
        SetLength(lMeshAttachment.Bones, Length(lVertices.Bones));
        TArray.Copy(lVertices.Vertices, lMeshAttachment.Vertices, 0, 0, Length(lVertices.Vertices));
        TArray.Copy(lVertices.Bones, lMeshAttachment.Bones, 0, 0, Length(lVertices.Bones));
        lMeshAttachment.WorldVerticesLength:= lVertexCount shl1;
        SetLength(lMeshAttachment.Triangles, Length(lTriangles));
        SetLength(lMeshAttachment.RegionUVs, Length(lUVs));
        TArray.Copy(lTriangles, lMeshAttachment.Triangles, 0, 0, Length(lTriangles));
        TArray.Copy(lUVs, lMeshAttachment.RegionUVs, 0, 0, Length(lUVs));
        lMeshAttachment.UpdateUVs();
        lMeshAttachment.HullLength:= lHullLength shl1;
        if ANonessential thenbegin
          TArray.Copy(lEdges, lMeshAttachment.Edges, 0, 0, Length(lEdges));
          lMeshAttachment.Width:= lWidth * Self.Scale;
          lMeshAttachment.Height:= lHeight * Self.Scale;
        end;
        exit(lMeshAttachment);
      end;
    TAttachmentType.atLinkedmesh:
      begin
        lPath:= Self.ReadString(AStream);
        lColor:= Self.ReadInt(AStream);
        lSkinName:= Self.ReadString(AStream);
        lParentMeshName:= Self.ReadString(AStream);
        lInheritDeform:= Self.ReadBoolean(AStream);
        lWidth:= 0;
        lHeight:= 0;
        if ANonessential thenbegin
          lWidth:= Self.ReadFloat(AStream);
          lHeight:= Self.ReadFloat(AStream);
        end;
        if lPath.Trim.IsEmpty then lPath:= lName;
        lMeshAttachment:= FAttachmentLoader.NewMeshAttachment(ASkin, lName, lPath);
        ifnot Assigned(lMeshAttachment) then exit(nil);
        lMeshAttachment.Path:= lPath;
        lMeshAttachment.R:= ((lColor and $ff) shr24) / 255;
        lMeshAttachment.G:= ((lColor and $00ff) shr16) / 255;
        lMeshAttachment.B:= ((lColor and $0000ff) shr8) / 255;
        lMeshAttachment.A:= ((lColor and $000000ff)) / 255;
        lMeshAttachment.InheritDeform:= lInheritDeform;
        if ANonessential thenbegin
          lMeshAttachment.Width:= lWidth * Self.Scale;
          lMeshAttachment.Height:= lHeight * Self.Scale;
        end;
        FLinkedMeshes.Add(TSkeletonJson.TLinkedMesh.Create(lMeshAttachment, lSkinName, ASlotIndex, lParentMeshName));
        exit(lMeshAttachment);
      end;
    TAttachmentType.atPath:
      begin
        lClosed:= Self.ReadBoolean(AStream);
        lConstantSpeed:= Self.ReadBoolean(AStream);
        lVertexCount:= Self.ReadVarint(AStream, True);
        lVertices:= Self.ReadVertices(AStream, lVertexCount);
        SetLength(lLengths, System.Math.Floor(lVertexCount / 3));
        for i:= 0to Length(lLengths) -1do
          lLengths[i]:= Self.ReadFloat(AStream) * Self.Scale;
        if ANonessential then Self.ReadInt(AStream);
        //
        lPathAttachment:= FAttachmentLoader.NewPathAttachment(ASkin, lName);
        ifnot Assigned(lPathAttachment) then exit(nil);
        lPathAttachment.Closed:= lClosed;
        lPathAttachment.ConstantSpeed:= lConstantSpeed;
        lPathAttachment.WorldVerticesLength:= lVertexCount shl1;
        SetLength(lPathAttachment.Vertices, Length(lVertices.Vertices));
        SetLength(lPathAttachment.Bones, Length(lVertices.Bones));
        SetLength(lPathAttachment.Lengths, Length(lLengths));
        TArray.Copy(lVertices.Vertices, lPathAttachment.Vertices, 0, 0, Length(lVertices.Vertices));
        TArray.Copy(lVertices.Bones, lPathAttachment.Bones, 0, 0, Length(lVertices.Bones));
        TArray.Copy(lLengths, lPathAttachment.Lengths, 0, 0, Length(lLengths));
        exit(lPathAttachment);
      end;
    TAttachmentType.atPoint:
      begin
        lRotation:= Self.ReadFloat(AStream);
        lX:= Self.ReadFloat(AStream);
        lY:= Self.ReadFloat(AStream);
        if ANonessential then Self.ReadInt(AStream);
        //
        lPointAttachment:= FAttachmentLoader.NewPointAttachment(ASkin, lName);
        ifnot Assigned(lPointAttachment) then exit(nil);
        lPointAttachment.X:= lX * Self.Scale;
        lPointAttachment.Y:= lY * Self.Scale;
        lPointAttachment.Rotation:= lRotation;
        exit(lPointAttachment);
      end;
    TAttachmentType.atClipping:
      begin
        lEndSlotIndex:= Self.ReadVarint(AStream, True);
        lVertexCount:= Self.ReadVarint(AStream, True);
        lVertices:= Self.ReadVertices(AStream, lVertexCount);
        if ANonessential then Self.ReadInt(AStream);
        //
        lClippingAttachment:= FAttachmentLoader.NewClippingAttachment(ASkin, lName);
        ifnot Assigned(lClippingAttachment) then exit(nil);
        lClippingAttachment.EndSlot:= ASkeletonData.SlotDatas.Items[lEndSlotIndex];
        lClippingAttachment.worldVerticesLength:= lVertexCount shl1;
        SetLength(lPathAttachment.Vertices, Length(lVertices.Vertices));
        SetLength(lPathAttachment.Bones, Length(lVertices.Bones));
        TArray.Copy(lVertices.Vertices, lClippingAttachment.Vertices, 0, 0, Length(lVertices.Vertices));
        TArray.Copy(lVertices.Bones, lClippingAttachment.Bones, 0, 0, Length(lVertices.Bones));
        exit(lClippingAttachment);
      end;
  end;
  result:= nil;
end;

function TSpineSkeletonBinary.ReadVertices(const AStream: TStream;
  const AVertexCount: Integer): TVertices;
var
  lVerticesLength, i, lBoneCount, j, idx1, idx2: Integer;
  lWeights: TArray;
begin
  lVerticesLength:= AVertexCount shl1;
  ifnot Self.ReadBoolean(AStream) thenbegin
    result.Vertices:= Self.ReadFloatArray(AStream, lVerticesLength, Self.Scale);
    exit;
  end;
  SetLength(result.Vertices, lVerticesLength * 3 * 3);
  SetLength(result.Bones, lVerticesLength * 3);
  idx1:= 0;
  idx2:= 0;
  for i:= 0to AVertexCount -1dobegin
    lBoneCount:= Self.ReadVarInt(AStream, True);
    result.Bones[idx1]:= Self.ReadVarInt(AStream, True);
    Inc(idx1);
    for j:= 0to lBoneCount -1dobegin
      result.Bones[idx1]:= Self.ReadVarInt(AStream, True);
      Inc(idx1);
      //
      result.Vertices[idx2]:= Self.ReadFloat(AStream) * Self.Scale;
      Inc(idx2);
      result.Vertices[idx2]:= Self.ReadFloat(AStream) * Self.Scale;
      Inc(idx2);
      result.Vertices[idx2]:= Self.ReadFloat(AStream);
      Inc(idx2);
    end;
  end;
end;

function TSpineSkeletonBinary.ReadFloatArray(const AStream: TStream;
  const ACount: Integer; const AScale: Single): TArray;
var
  i: Integer;
begin
  SetLength(result, ACount);
  if AScale = 1thenbeginfor i:= 0to ACount -1do
      result[i]:= Self.ReadFloat(AStream);
  endelsebeginfor i:= 0to ACount -1do
      result[i]:= Self.ReadFloat(AStream) * AScale;
  end;
end;

function TSpineSkeletonBinary.ReadShortArray(
  const AStream: TStream): TArray;
var
  lCount, i: Integer;
begin
  lCount:= Self.ReadVarInt(AStream, True);
  SetLength(result, lCount);
  for i:= 0to lCount -1do
    result[i]:= (Self.ReadByte(AStream) shl8) or Self.ReadByte(AStream);
end;

procedure TSpineSkeletonBinary.ReadAnimation(const AName: string;
  const AStream: TStream; const ASkeletonData: TSkeletonData);
var
  lAnimation: TSpineAnimation;
  lDuration: Single;
  i, n, lIndex, j, nn, lTimelineType, lFrameCount, k, nnn: Integer;
  lAttachmentTimeline: TAttachmentTimeline;
  lFrameIndex: Integer;
  lColorTimeline: TColorTimeline;
  lTime, lR, lG, lB, lA, lR2, lG2, lB2: Single;
  lColor, lColor2: Integer;
  lTwoColorTimeline: TTwoColorTimeline;
  lRotateTimeline: TRotateTimeline;
  lTranslateTimeline: TTranslateTimeline;
  lTimelineScale: Single;
  lIkConstraintTimeline: TIkConstraintTimeline;
  lTransformConstraintTimeline: TTransformConstraintTimeline;
  lPathConstraintData: TPathConstraintData;
  lPathConstraintPositionTimeline: TPathConstraintPositionTimeline;
  lPathConstraintMixTimeline: TPathConstraintMixTimeline;
  lSkin: TSpineSkin;
  lVertexAttachment: TVertexAttachment;
  lWeighted: Boolean;
  v: Integer;
  lDeformLength: Integer;
  lDeformTiemline: TDeformTimeline;
  lDeform: TArray;
  lStart, lEnd: Integer;
  lDrawOrderTimeline: TDrawOrderTimeline;
  lSlotCount, lOffsetCount: Integer;
  lDrawOrder, lUnChanged: TArray;
  lOriginalIndex, lUnChangedIndex: Integer;
  lEventTimeline: TEventTimeline;
  lEventData: TEventData;
  lEvent: TSpineEvent;
begin
  lAnimation:= TSpineAnimation.Create(AName, 0);
  try
    lDuration:= 0;

    // Slot timelines.
    n:= Self.ReadVarInt(AStream, True);
    for i:= 0to n -1dobegin
      lIndex:= Self.ReadVarInt(AStream, True);  //slotindex
      nn:= Self.ReadVarInt(AStream, True);
      for j:= 0to nn -1dobegin
        lTimelineType:= Self.ReadByte(AStream);
        lFrameCount:= Self.ReadVarInt(AStream, True);
        case lTimelineType of
          SLOT_ATTACHMENT:
            begin
              lAttachmentTimeline:= TAttachmentTimeline.Create(lFrameCount);
              lAttachmentTimeline.SlotIndex:= lIndex;
              for lFrameIndex:= 0to lFrameCount -1do
                lAttachmentTimeline.SetFrame(lFrameIndex, Self.ReadFloat(AStream), Self.ReadString(AStream));
              lAnimation.Timelines.Add(lAttachmentTimeline);
              lDuration:= System.Math.Max(lDuration, lAttachmentTimeline.Frames[lFrameCount-1]);
            end;
          SLOT_COLOR:
            begin
              lColorTimeline:= TColorTimeline.Create(lFrameCount);
              lColorTimeline.SlotIndex:= lIndex;
              for lFrameIndex:= 0to lFrameCount -1dobegin
                lTime:= Self.ReadFloat(AStream);
                lColor:= Self.ReadInt(AStream);
                lR:= ((lColor and $ff) shr24) / 255;
                lG:= ((lColor and $00ff) shr16) / 255;
                lB:= ((lColor and $0000ff) shr8) / 255;
                lA:= ((lColor and $000000ff)) / 255;
                lColorTimeline.SetFrame(lFrameIndex, lTime, lR, lG, lB, lA);
                if lFrameIndex < lFrameCount - 1then Self.ReadCurve(AStream, lFrameIndex, lColorTimeline);
              end;
              lAnimation.Timelines.Add(lColorTimeline);
              lDuration:= System.Math.Max(lDuration, lColorTimeline.Frames[(lColorTimeline.FrameCount-1)*TColorTimeline.ENTRIES]);
            end;
          SLOT_TWO_COLOR:
            begin
              lTwoColorTimeline:= TTwoColorTimeline.Create(lFrameCount);
              lTwoColorTimeline.SlotIndex:= lIndex;
              for lFrameIndex:= 0to lFrameCount -1dobegin
                lTime:= Self.ReadFloat(AStream);
                lColor:= Self.ReadInt(AStream);
                lR:= ((lColor and $ff) shr24) / 255;
                lG:= ((lColor and $00ff) shr16) / 255;
                lB:= ((lColor and $0000ff) shr8) / 255;
                lA:= ((lColor and $000000ff)) / 255;
                lColor2:= Self.ReadInt(AStream); // 0x00rrggbb
                lR2:= ((lColor2 and $00ff) shr16) / 255;
                lG2:= ((lColor2 and $0000ff) shr8) / 255;
                lB2:= ((lColor2 and $000000ff)) / 255;
                lTwoColorTimeline.SetFrame(lFrameIndex, lTime, lR, lG, lB, lA, lR2, lG2, lB2);
                if lFrameIndex < lFrameCount - 1then Self.ReadCurve(AStream, lFrameIndex, lTwoColorTimeline);
              end;
              lAnimation.Timelines.Add(lTwoColorTimeline);
              lDuration:= System.Math.Max(lDuration, lTwoColorTimeline.Frames[(lColorTimeline.FrameCount-1)*TTwoColorTimeline.ENTRIES]);
            end;
        end;
      end;
    end;

    // Bone timelines.
    n:= Self.ReadVarInt(AStream, True);
    for i:= 0to n -1dobegin
      lIndex:= Self.ReadVarInt(AStream, True);        //boneindex
      nn:= Self.ReadVarInt(AStream, True);
      for j:= 0to nn -1dobegin
        lTimelineType:= Self.ReadByte(AStream);
        lFrameCount:= Self.ReadVarInt(AStream, True);
        case lTimelineType of
          BONE_ROTATE:
            begin
              lRotateTimeline:= TRotateTimeline.Create(lFrameCount);
              lRotateTimeline.BoneIndex:= lIndex;
              for lFrameIndex:= 0to lFrameCount -1dobegin
                lRotateTimeline.SetFrame(lFrameIndex, Self.ReadFloat(AStream), Self.ReadFloat(AStream));
                if lFrameIndex < lFrameCount - 1then Self.ReadCurve(AStream, lFrameIndex, lRotateTimeline);
              end;
              lAnimation.Timelines.Add(lRotateTimeline);
              lDuration:= System.Math.Max(lDuration, lRotateTimeline.Frames[(lFrameCount-1) * TRotateTimeline.ENTRIES]);
            end;
          BONE_TRANSLATE, BONE_SCALE, BONE_SHEAR:
            begin
              lTimelineScale:= 1;
              case lTimelineType of
                BONE_SCALE: lTranslateTimeline:= TScaleTimeline.Create(lFrameCount);
                BONE_SHEAR: lTranslateTimeline:= TShearTimeline.Create(lFrameCount);
                elsebegin
                  lTranslateTimeline:= TTranslateTimeline.Create(lFrameCount);
                  lTimelineScale:= Self.Scale;
                end;
              end;
              lTranslateTimeline.BoneIndex:= lIndex;
              for lFrameIndex:= 0to lFrameCount -1dobegin
                lTranslateTimeline.SetFrame(lFrameIndex, Self.ReadFloat(AStream),
                  Self.ReadFloat(AStream) * lTimelineScale, Self.ReadFloat(AStream) * lTimelineScale);
                if lFrameIndex < lFrameCount - 1then Self.ReadCurve(AStream, lFrameIndex, lTranslateTimeline);
              end;
              lAnimation.Timelines.Add(lTranslateTimeline);
              lDuration:= System.Math.Max(lDuration, lTranslateTimeline.Frames[(lFrameCount-1) * TTranslateTimeline.ENTRIES]);
            end;
        end;
      end;
    end;

    // IK timelines.
    n:= Self.ReadVarInt(AStream, True);
    for i:= 0to n -1dobegin
      lIndex:= Self.ReadVarInt(AStream, True);        //IkConstraintIndex
      lFrameCount:= Self.ReadVarInt(AStream, True);
      lIkConstraintTimeline:= TIkConstraintTimeline.Create(lFrameCount);
      lIkConstraintTimeline.IkConstraintIndex:= lIndex;
      for lFrameIndex:= 0to lFrameCount -1dobegin
        lIkConstraintTimeline.SetFrame(lFrameIndex, Self.ReadFloat(AStream),
          Self.ReadFloat(AStream), Self.ReadSByte(AStream));
        if lFrameIndex < lFrameCount - 1then Self.ReadCurve(AStream, lFrameIndex, lIkConstraintTimeline);
      end;
      lAnimation.Timelines.Add(lIkConstraintTimeline);
      lDuration:= System.Math.Max(lDuration, lIkConstraintTimeline.Frames[(lFrameCount-1) * TIkConstraintTimeline.ENTRIES]);
    end;

    // Transform constraint timelines.
    n:= Self.ReadVarInt(AStream, True);
    for i:= 0to n -1dobegin
      lIndex:= Self.ReadVarInt(AStream, True);          //TransformConstraintIndex
      lFrameCount:= Self.ReadVarInt(AStream, True);
      lTransformConstraintTimeline:= TTransformConstraintTimeline.Create(lFrameCount);
      lTransformConstraintTimeline.TransformConstraintIndex:= lIndex;
      for lFrameIndex:= 0to lFrameCount -1dobegin
        lTransformConstraintTimeline.SetFrame(lFrameIndex, Self.ReadFloat(AStream),
          Self.ReadFloat(AStream), Self.ReadFloat(AStream), Self.ReadFloat(AStream), Self.ReadFloat(AStream));
        if lFrameIndex < lFrameCount - 1then Self.ReadCurve(AStream, lFrameIndex, lTransformConstraintTimeline);
      end;
      lAnimation.Timelines.Add(lTransformConstraintTimeline);
      lDuration:= System.Math.Max(lDuration, lTransformConstraintTimeline.Frames[(lFrameCount-1) * TTransformConstraintTimeline.ENTRIES]);
    end;

    // Path constraint timelines.
    n:= Self.ReadVarInt(AStream, True);
    for i:= 0to n -1dobegin
      lIndex:= Self.ReadVarInt(AStream, True);         //PathConstraintIndex
      lPathConstraintData:= ASkeletonData.PathConstraintDatas.Items[lIndex];
      nn:= Self.ReadVarInt(AStream, True);
      for j:= 0to nn -1dobegin
        lTimelineType:= Self.ReadSByte(AStream);
        lFrameCount:= Self.ReadVarInt(AStream, True);
        case lTimelineType of
          PATH_POSITION, PATH_SPACING:
            begin
              lTimelineScale:= 1;
              if lTimelineType = PATH_SPACING thenbegin
                lPathConstraintPositionTimeline:= TPathConstraintSpacingTimeline.Create(lFrameCount);
                if (lPathConstraintData.SpacingMode = TSpacingMode.smLength) or
                   (lPathConstraintData.SpacingMode = TSpacingMode.smFixed) then
                  lTimelineScale:= Self.Scale;
              endelsebegin
                lPathConstraintPositionTimeline:= TPathConstraintPositionTimeline.Create(lFrameCount);
                if lPathConstraintData.PositionMode = TPositionMode.pmFixed then
                  lTimelineScale:= Self.Scale;
              end;
              lPathConstraintPositionTimeline.PathConstraintIndex:= lIndex;
              for lFrameIndex:= 0to lFrameCount -1dobegin
                lPathConstraintPositionTimeline.SetFrame(lFrameIndex, Self.ReadFloat(AStream), Self.ReadFloat(AStream) * lTimelineScale);
                if lFrameIndex < lFrameCount - 1then Self.ReadCurve(AStream, lFrameIndex, lPathConstraintPositionTimeline);
              end;
              lAnimation.Timelines.Add(lPathConstraintPositionTimeline);
              lDuration:= System.Math.Max(lDuration, lPathConstraintPositionTimeline.Frames[(lFrameCount-1) * TPathConstraintPositionTimeline.ENTRIES]);
            end;
          PATH_MIX:
            begin
              lPathConstraintMixTimeline:= TPathConstraintMixTimeline.Create(lFrameCount);
              lPathConstraintMixTimeline.PathConstraintIndex:= lIndex;
              for lFrameIndex:= 0to lFrameCount -1dobegin
                lPathConstraintMixTimeline.SetFrame(lFrameIndex, Self.ReadFloat(AStream),
                  Self.ReadFloat(AStream), Self.ReadFloat(AStream));
                if lFrameIndex < lFrameCount - 1then Self.ReadCurve(AStream, lFrameIndex, lPathConstraintMixTimeline);
              end;
              lAnimation.Timelines.Add(lPathConstraintMixTimeline);
              lDuration:= System.Math.Max(lDuration, lPathConstraintMixTimeline.Frames[(lFrameCount-1) * TPathConstraintMixTimeline.ENTRIES]);
            end;
        end;
      end;
    end;

    // Deform timelines.
    n:= Self.ReadVarInt(AStream, True);
    for i:= 0to n -1dobegin
      lSkin:= ASkeletonData.Skins.Items[Self.ReadVarInt(AStream, True)];
      nn:= Self.ReadVarInt(AStream, True);
      for j:= 0to nn -1dobegin
        lIndex:= Self.ReadVarInt(AStream, True);         //slotindex
        nnn:= Self.ReadVarInt(AStream, True);
        for k:= 0to nnn -1dobegin
          lVertexAttachment:= TVertexAttachment(lSkin.GetAttachment(lIndex, Self.ReadString(AStream)));
          lWeighted:= Length(lVertexAttachment.Bones) > 0;
          if lWeighted then
            lDeformLength:= System.Math.Floor(Length(lVertexAttachment.Vertices) / 3 *2)
          else
            lDeformLength:= Length(lVertexAttachment.Vertices);
          lFrameCount:= Self.ReadVarInt(AStream, True);
          lDeformTiemline:= TDeformTimeline.Create(lFrameCount);
          lDeformTiemline.SlotIndex:= lIndex;
          lDeformTiemline.Attachment:= lVertexAttachment;
          for lFrameIndex:= 0to lFrameCount -1dobegin
            lTime:= Self.ReadFloat(AStream);
            lEnd:= Self.ReadVarInt(AStream, True);
            if lEnd = 0thenbeginif lWeighted then
                SetLength(lDeform, lDeformLength)
              else
                lDeform:= lVertexAttachment.Vertices;
            endelsebegin
              SetLength(lDeform, lDeformLength);
              lStart:= Self.ReadVarInt(AStream, True);
              lEnd:= lEnd + lStart;
              if Self.Scale = 1thenbeginfor v:= lStart to lEnd -1do
                  lDeform[v]:= Self.ReadFloat(AStream);
              endelsebeginfor v:= lStart to lEnd -1do
                  lDeform[v]:= Self.ReadFloat(AStream) * Self.Scale;
              end;
              ifnot lWeighted thenfor v:= 0to Length(lDeform) -1do
                  lDeform[v]:= lDeform[v] + lVertexAttachment.Vertices[v];
            end;
            lDeformTiemline.SetFrame(lFrameIndex, lTime, lDeform);
            if lFrameIndex < lFrameCount -1then Self.ReadCurve(AStream, lFrameIndex, lDeformTiemline);
          end;
          lAnimation.Timelines.Add(lDeformTiemline);
          lDuration:= System.Math.Max(lDuration, lDeformTiemline.Frames[lFrameCount -1]);
        end;
      end;
    end;

    // Draw order timeline.
    n:= Self.ReadVarInt(AStream, True); //drawOrderCountif n > 0thenbegin
      lDrawOrderTimeline:= TDrawOrderTimeline.Create(n);
      lSlotCount:= ASkeletonData.SlotDatas.Count;
      for i:= 0to n -1dobegin
        lTime:= Self.ReadFloat(AStream);
        lOffsetCount:= Self.ReadVarInt(AStream, True);
        SetLength(lDrawOrder, lSlotCount);
        for j:= lSlotCount -1downto0do
          lDrawOrder[j]:= -1;
        SetLength(lUnChanged, lSlotCount - lOffsetCount);
        lOriginalIndex:= 0;
        lUnChangedIndex:= 0;
        for j:= 0to lOffsetCount -1dobegin
          lIndex:= Self.ReadVarInt(AStream, True); //slotindex// Collect unchanged items.while lOriginalIndex <> lIndex dobegin
            lUnChanged[lUnChangedIndex]:= lOriginalIndex;
            Inc(lUnChangedIndex);
            Inc(lOriginalIndex);
          end;
          lDrawOrder[lOriginalIndex+Self.ReadVarInt(AStream, True)]:= lOriginalIndex;
          Inc(lOriginalIndex);
        end;
        // Collect remaining unchanged items.while lOriginalIndex < lSlotCount dobegin
          lUnChanged[lUnChangedIndex]:= lOriginalIndex;
          Inc(lUnChangedIndex);
          Inc(lOriginalIndex);
        end;
        // Fill in unchanged items.for j:= lSlotCount downto0dobeginif lDrawOrder[j] = -1thenbegin
            Dec(lUnChangedIndex);
            lDrawOrder[j]:= lUnChanged[lUnChangedIndex];
          end;
        end;
        lDrawOrderTimeline.SetFrame(i, lTime, lDrawOrder);
      end;
      lAnimation.Timelines.Add(lDrawOrderTimeline);
      lDuration:= System.Math.Max(lDuration, lDrawOrderTimeline.Frames[lFrameCount -1]);
    end;

    // Event timeline.
    n:= Self.ReadVarInt(AStream, True); //eventCountif n > 0thenbegin
      lEventTimeline:= TEventTimeline.Create(n);
      for i:= 0to n -1dobegin
        lTime:= Self.ReadFloat(AStream);
        lEventData:= ASkeletonData.EventDatas.Items[Self.ReadVarInt(AStream, True)];
        lEvent:= TSpineEvent.Create(lTime, lEventData);
        lEvent.IntValue:= Self.ReadVarInt(AStream, False);
        lEvent.FloatValue:= Self.ReadFloat(AStream);
        if Self.ReadBoolean(AStream) then
          lEvent.StringValue:= Self.ReadString(AStream)
        else
          lEvent.StringValue:= lEventData.StringValue;
        lEventTimeline.SetFrame(i, lEvent);
      end;
      lAnimation.Timelines.Add(lEventTimeline);
      lDuration:= System.Math.Max(lDuration, lEventTimeline.Frames[lFrameCount -1]);
    end;
    lAnimation.Timelines.TrimExcess;
    lAnimation.Duration:= lDuration;
    ASkeletonData.Animations.Add(lAnimation);
  except
    lAnimation.Free;
    raise;
  end;
end;

procedure TSpineSkeletonBinary.ReadCurve(const AStream: TStream;
  const AFrameIndex: Integer; const ATimeline: TCurveTimeline);
begincase Self.ReadByte(AStream) of
    CURVE_STEPPED: ATimeline.SetStepped(AFrameIndex);
    CURVE_BEZIER: ATimeline.SetCurve(AFrameIndex, Self.ReadFloat(AStream),
      Self.ReadFloat(AStream), Self.ReadFloat(AStream), Self.ReadFloat(AStream));
  end;
end;

function TSpineSkeletonBinary.ReadSByte(const AStream: TStream): SByte;
var
  lValue: Integer;
begin
  lValue:= Self.ReadByte(AStream);
  if lValue = -1thenraise Exception.Create('end of stream.');
  result:= lValue;
end;

function TSpineSkeletonBinary.ReadBoolean(const AStream: TStream): Boolean;
begin
  result:= Self.ReadByte(AStream) <> 0;
end;

function TSpineSkeletonBinary.ReadFloat(const AStream: TStream): Single;
begin
  FBuffer[3]:= Self.ReadByte(AStream);
  FBuffer[2]:= Self.ReadByte(AStream);
  FBuffer[1]:= Self.ReadByte(AStream);
  FBuffer[0]:= Self.ReadByte(AStream);
  result:= PSingle(@FBuffer[0])^;
end;

function TSpineSkeletonBinary.ReadInt(const AStream: TStream): Integer;
begin
  result:= Self.ReadByte(AStream) shl24;
  result:= result + (Self.ReadByte(AStream) shl16);
  result:= result + (Self.ReadByte(AStream) shl8);
  result:= result + Self.ReadByte(AStream);
end;

function TSpineSkeletonBinary.ReadVarInt(const AStream: TStream;
  const AOptimizePositive: Boolean): Integer;
var
  lByte: Integer;
begin
  lByte:= Self.ReadByte(AStream);
  result:= lByte and $7F;
  if (lByte and $80) <> 0thenbegin
    lByte:= Self.ReadByte(AStream);
    result:= result or ((lByte and $7F) shl7);
    if (lByte and $80) <> 0thenbegin
      lByte:= Self.ReadByte(AStream);
      result:= result or ((lByte and $7F) shl14);
      if (lByte and $80) <> 0thenbegin
        lByte:= Self.ReadByte(AStream);
        result:= result or ((lByte and $7F) shl21);
        if (lByte and $80) <> 0then
          result:= result or ((lByte and $7F) shl28);
      end;
    end;
  end;
  //
ifnot AOptimizePositive then
    result:= (((Result shr1) and $7fffffff) xor -(Result and1));
end;

function TSpineSkeletonBinary.ReadString(const AStream: TStream): string;
var
  lByteCount: Integer;
  lBuffer: TArray;
begin
  lByteCount:= Self.ReadVarInt(AStream, True);
  case lByteCount of0, 1: exit('');
    elsebegin
        lByteCount:= lByteCount - 1;
        if Length(lBuffer) < lByteCount then
          SetLength(lBuffer, lByteCount)
        else
          TArray.Copy(FBuffer, lBuffer, 0, 0, Length(FBuffer));
        TSpineSkeletonBinary.ReadFully(AStream, lBuffer, 0, lByteCount);
        result:= System.SysUtils.StringOf(lBuffer);
      end;
  end;
end;

classprocedure TSpineSkeletonBinary.ReadFully(const AStream: TStream;
  var ABuffer: TArray; const AOffset: Integer; var ALength: Integer);
var
  lOffset, lCount: Integer;
begin
  lOffset:= AOffset;
  while ALength > 0dobegin
    lCount:= AStream.Read(ABuffer, lOffset, ALength);
    if lCount <= 0thenraise Exception.Create('end of stream.');
    lOffset:= lOffset + lCount;
    ALength:= ALength - lCount;
  end;
end;

end.

上一篇翻译了图集解析单元,今天把骨架解析也翻译完了(二进制,.skel文件)。1000多行代码,把我累的。。。

spine.core.bone, spine.core.slot, spine.core.skin,
spine.core.attachment, spine.core.constraint, spine.core.skeleton,
spine.core.animation.timeline, spine.core.skeleton.json, spine.core.event,
spine.core.animation

上面这些依赖的单元部分还在整理,慢慢放上来。

到现在为止,算是把基本数据的解析工作完成了。

以上就介绍了 Spine Runtime for Delphi移植笔记(六) - spinecoreskeletonbinary,包括了方面的内容,希望对Delphijrs看球网直播吧_低调看直播体育app软件下载_低调看体育直播有兴趣的朋友有所帮助。

本文网址链接:http://www.codes51.com/article/detail_4417405.html

相关图片

相关文章