【Spine】Spine Runtime for Delphi移植笔记(六)

2017-08-02 11:33:45来源:cnblogs.com作者:spine.core.skeleton.binary - 水人点击

分享
//////////////////////////////////////////////////////////////////////////////////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 = class  public const        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;  private type        TVertices = record            Bones: TArray<Integer>;            Vertices: TArray<Single>;        end;  private    FLinkedMeshes: TObjectList<TSkeletonJson.TLinkedMesh>;    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<Integer>;    function ReadFloatArray(const AStream: TStream; const ACount: Integer;      const AScale: Single): TArray<Single>;    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);    class procedure ReadFully(const AStream: TStream; var ABuffer: TArray<Byte>;      const AOffset: Integer; var ALength: Integer); static;  public    Scale: Single;    constructor Create(const AAtlasArray: TArray<TSpineAtlas>); overload;    constructor Create(const AAttachmentLoader: TAttachmentLoader); overload;    destructor Destroy; override;    function ReadSkeletonData(const ASkelFile: string): TSkeletonData; overload;    function ReadSkeletonData(const ASkelStream: TStream): TSkeletonData; overload;  end;implementation{ TSpineSkeletonBinary }constructor TSpineSkeletonBinary.Create(const AAtlasArray: TArray<TSpineAtlas>);begin  FAttachmentLoader:= TAtlasAttachmentLoader.Create(AAtlasArray);  Create(FAttachmentLoader);end;constructor TSpineSkeletonBinary.Create(  const AAttachmentLoader: TAttachmentLoader);begin  inherited Create;  if not Assigned(AAttachmentLoader) then raise Exception.Create('attachmentLoader cannot be null.');  FLinkedMeshes:= TObjectList<TSkeletonJson.TLinkedMesh>.Create;  FAttachmentLoader:= AAttachmentLoader;end;destructor TSpineSkeletonBinary.Destroy;begin  FLinkedMeshes.Free;  if Assigned(FAttachmentLoader) then FreeAndNil(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;begin  if not Assigned(ASkelStream) then raise 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 then  begin    result.FPS:= Self.ReadFloat(ASkelStream);    result.ImagesPath:= Self.ReadString(ASkelStream);  end;  // Bones.  n:= Self.ReadVarInt(ASkelStream, True);  for i:= 0 to n -1 do  begin    lName:= Self.ReadString(ASkelStream);    if i = 0 then      lBoneDataParent:= nil    else      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:= 0 to n -1 do  begin    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) shr 24) / 255;    lSlotData.G:= ((lColor and $00ff) shr 16) / 255;    lSlotData.B:= ((lColor and $0000ff) shr 8) / 255;    lSlotData.A:= (lColor and $000000ff) / 255;    lDarkColor:= Self.ReadInt(ASkelStream); // 0x00rrggbb    if lDarkColor <> -1 then    begin      lSlotData.HasSecondColor:= True;      lSlotData.R2:= ((lDarkColor and $00ff) shr 16) / 255;      lSlotData.G2:= ((lDarkColor and $0000ff) shr 8) / 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:= 0 to n -1 do  begin    lIkConstraintData:= TIkConstraintData.Create(Self.ReadString(ASkelStream));    lIkConstraintData.Order:= Self.ReadVarInt(ASkelStream, True);    nn:= Self.ReadVarInt(ASkelStream, True);    for j:= 0 to nn -1 do      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:= 0 to n -1 do  begin    lTransformConstraintData:= TTransformConstraintData.Create(Self.ReadString(ASkelStream));    lTransformConstraintData.Order:= Self.ReadVarInt(ASkelStream, True);    nn:= Self.ReadVarInt(ASkelStream, True);    for j:= 0 to nn -1 do      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:= 0 to n -1 do  begin    lPathConstraintData:= TPathConstraintData.Create(Self.ReadString(ASkelStream));    lPathConstraintData.Order:= Self.ReadVarInt(ASkelStream, True);    nn:= Self.ReadVarInt(ASkelStream, True);    for j:= 0 to nn -1 do      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) then  begin    result.DefaultSkin:= lDefaultSkin;    result.Skins.Add(lDefaultSkin);  end;  // Skins.  n:= Self.ReadVarInt(ASkelStream, True);  for i:= 0 to n -1 do    result.Skins.Add(Self.ReadSkin(ASkelStream, result, Self.ReadString(ASkelStream), lNonessential));  // Linked meshes.  n:= FLinkedMeshes.Count;  for i:= 0 to n -1 do  begin    lLinkedMesh:= FLinkedMeshes[i];    if not Assigned(lLinkedMesh) then      lSkin:= lDefaultSkin    else      lSkin:= result.FindSkin(lLinkedMesh.Skin);    if not Assigned(lSkin) then raise Exception.CreateFmt('Skin not found: %s',[lLinkedMesh.Skin]);    lParentAttachment:= lSkin.GetAttachment(lLinkedMesh.SlotIndex, lLinkedMesh.Parent);    if not Assigned(lParentAttachment) then raise 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:= 0 to n -1 do  begin    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:= 0 to n -1 do    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;begin  if 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 = 0 then exit(nil);  result:= TSpineSkin.Create;  for i:= 0 to lSlotCount -1 do  begin    lSlotIndex:= Self.ReadVarInt(AStream, True);    n:= Self.ReadVarInt(AStream, True);    for j:= 0 to n -1 do    begin      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<Single>;  lTriangles, lEdges: TArray<Integer>;  lHullLength: Integer;  lMeshAttachment: TMeshAttachment;  lSkinName, lParentMeshName: string;  lInheritDeform: Boolean;  lClosed, lConstantSpeed: Boolean;  lLengths: TArray<Single>;  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);        if not 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) shr 24) / 255;        lRegionAttachment.G:= ((lColor and $00ff) shr 16) / 255;        lRegionAttachment.B:= ((lColor and $0000ff) shr 8) / 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);        if not Assigned(lBoxAttachment) then exit(nil);        lBoxAttachment.WorldVerticesLength:= lVertexCount shl 1;        SetLength(lBoxAttachment.Vertices, Length(lVertices.Vertices));        SetLength(lBoxAttachment.Bones, Length(lVertices.Bones));        TArray.Copy<Single>(lVertices.Vertices, lBoxAttachment.Vertices, 0, 0, Length(lVertices.Vertices));        TArray.Copy<Integer>(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 shl 1, 1);        lTriangles:= Self.ReadShortArray(AStream);        lVertices:= Self.ReadVertices(AStream, lVertexCount);        lHullLength:= Self.ReadVarInt(AStream, True);        lWidth:= 0;        lHeight:= 0;        if ANonessential then        begin          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);        if not Assigned(lMeshAttachment) then exit(nil);        lMeshAttachment.Path:= lPath;        lMeshAttachment.R:= ((lColor and $ff) shr 24) / 255;        lMeshAttachment.G:= ((lColor and $00ff) shr 16) / 255;        lMeshAttachment.B:= ((lColor and $0000ff) shr 8) / 255;        lMeshAttachment.A:= ((lColor and $000000ff)) / 255;        SetLength(lMeshAttachment.Vertices, Length(lVertices.Vertices));        SetLength(lMeshAttachment.Bones, Length(lVertices.Bones));        TArray.Copy<Single>(lVertices.Vertices, lMeshAttachment.Vertices, 0, 0, Length(lVertices.Vertices));        TArray.Copy<Integer>(lVertices.Bones, lMeshAttachment.Bones, 0, 0, Length(lVertices.Bones));        lMeshAttachment.WorldVerticesLength:= lVertexCount shl 1;        SetLength(lMeshAttachment.Triangles, Length(lTriangles));        SetLength(lMeshAttachment.RegionUVs, Length(lUVs));        TArray.Copy<Integer>(lTriangles, lMeshAttachment.Triangles, 0, 0, Length(lTriangles));        TArray.Copy<Single>(lUVs, lMeshAttachment.RegionUVs, 0, 0, Length(lUVs));        lMeshAttachment.UpdateUVs();        lMeshAttachment.HullLength:= lHullLength shl 1;        if ANonessential then        begin          TArray.Copy<Integer>(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 then        begin          lWidth:= Self.ReadFloat(AStream);          lHeight:= Self.ReadFloat(AStream);        end;        if lPath.Trim.IsEmpty then lPath:= lName;        lMeshAttachment:= FAttachmentLoader.NewMeshAttachment(ASkin, lName, lPath);        if not Assigned(lMeshAttachment) then exit(nil);        lMeshAttachment.Path:= lPath;        lMeshAttachment.R:= ((lColor and $ff) shr 24) / 255;        lMeshAttachment.G:= ((lColor and $00ff) shr 16) / 255;        lMeshAttachment.B:= ((lColor and $0000ff) shr 8) / 255;        lMeshAttachment.A:= ((lColor and $000000ff)) / 255;        lMeshAttachment.InheritDeform:= lInheritDeform;        if ANonessential then        begin          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:= 0 to Length(lLengths) -1 do          lLengths[i]:= Self.ReadFloat(AStream) * Self.Scale;        if ANonessential then Self.ReadInt(AStream);        //        lPathAttachment:= FAttachmentLoader.NewPathAttachment(ASkin, lName);        if not Assigned(lPathAttachment) then exit(nil);        lPathAttachment.Closed:= lClosed;        lPathAttachment.ConstantSpeed:= lConstantSpeed;        lPathAttachment.WorldVerticesLength:= lVertexCount shl 1;        SetLength(lPathAttachment.Vertices, Length(lVertices.Vertices));        SetLength(lPathAttachment.Bones, Length(lVertices.Bones));        SetLength(lPathAttachment.Lengths, Length(lLengths));        TArray.Copy<Single>(lVertices.Vertices, lPathAttachment.Vertices, 0, 0, Length(lVertices.Vertices));        TArray.Copy<Integer>(lVertices.Bones, lPathAttachment.Bones, 0, 0, Length(lVertices.Bones));        TArray.Copy<Single>(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);        if not 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);        if not Assigned(lClippingAttachment) then exit(nil);        lClippingAttachment.EndSlot:= ASkeletonData.SlotDatas.Items[lEndSlotIndex];        lClippingAttachment.worldVerticesLength:= lVertexCount shl 1;        SetLength(lPathAttachment.Vertices, Length(lVertices.Vertices));        SetLength(lPathAttachment.Bones, Length(lVertices.Bones));        TArray.Copy<Single>(lVertices.Vertices, lClippingAttachment.Vertices, 0, 0, Length(lVertices.Vertices));        TArray.Copy<Integer>(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<Single>;begin  lVerticesLength:= AVertexCount shl 1;  if not Self.ReadBoolean(AStream) then  begin    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:= 0 to AVertexCount -1 do  begin    lBoneCount:= Self.ReadVarInt(AStream, True);    result.Bones[idx1]:= Self.ReadVarInt(AStream, True);    Inc(idx1);    for j:= 0 to lBoneCount -1 do    begin      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<Single>;var  i: Integer;begin  SetLength(result, ACount);  if AScale = 1 then  begin    for i:= 0 to ACount -1 do      result[i]:= Self.ReadFloat(AStream);  end else  begin    for i:= 0 to ACount -1 do      result[i]:= Self.ReadFloat(AStream) * AScale;  end;end;function TSpineSkeletonBinary.ReadShortArray(  const AStream: TStream): TArray<Integer>;var  lCount, i: Integer;begin  lCount:= Self.ReadVarInt(AStream, True);  SetLength(result, lCount);  for i:= 0 to lCount -1 do    result[i]:= (Self.ReadByte(AStream) shl 8) 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<Single>;  lStart, lEnd: Integer;  lDrawOrderTimeline: TDrawOrderTimeline;  lSlotCount, lOffsetCount: Integer;  lDrawOrder, lUnChanged: TArray<Integer>;  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:= 0 to n -1 do    begin      lIndex:= Self.ReadVarInt(AStream, True);  //slotindex      nn:= Self.ReadVarInt(AStream, True);      for j:= 0 to nn -1 do      begin        lTimelineType:= Self.ReadByte(AStream);        lFrameCount:= Self.ReadVarInt(AStream, True);        case lTimelineType of          SLOT_ATTACHMENT:            begin              lAttachmentTimeline:= TAttachmentTimeline.Create(lFrameCount);              lAttachmentTimeline.SlotIndex:= lIndex;              for lFrameIndex:= 0 to lFrameCount -1 do                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:= 0 to lFrameCount -1 do              begin                lTime:= Self.ReadFloat(AStream);                lColor:= Self.ReadInt(AStream);                lR:= ((lColor and $ff) shr 24) / 255;                lG:= ((lColor and $00ff) shr 16) / 255;                lB:= ((lColor and $0000ff) shr 8) / 255;                lA:= ((lColor and $000000ff)) / 255;                lColorTimeline.SetFrame(lFrameIndex, lTime, lR, lG, lB, lA);                if lFrameIndex < lFrameCount - 1 then 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:= 0 to lFrameCount -1 do              begin                lTime:= Self.ReadFloat(AStream);                lColor:= Self.ReadInt(AStream);                lR:= ((lColor and $ff) shr 24) / 255;                lG:= ((lColor and $00ff) shr 16) / 255;                lB:= ((lColor and $0000ff) shr 8) / 255;                lA:= ((lColor and $000000ff)) / 255;                lColor2:= Self.ReadInt(AStream); // 0x00rrggbb                lR2:= ((lColor2 and $00ff) shr 16) / 255;                lG2:= ((lColor2 and $0000ff) shr 8) / 255;                lB2:= ((lColor2 and $000000ff)) / 255;                lTwoColorTimeline.SetFrame(lFrameIndex, lTime, lR, lG, lB, lA, lR2, lG2, lB2);                if lFrameIndex < lFrameCount - 1 then 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:= 0 to n -1 do    begin      lIndex:= Self.ReadVarInt(AStream, True);        //boneindex      nn:= Self.ReadVarInt(AStream, True);      for j:= 0 to nn -1 do      begin        lTimelineType:= Self.ReadByte(AStream);        lFrameCount:= Self.ReadVarInt(AStream, True);        case lTimelineType of          BONE_ROTATE:            begin              lRotateTimeline:= TRotateTimeline.Create(lFrameCount);              lRotateTimeline.BoneIndex:= lIndex;              for lFrameIndex:= 0 to lFrameCount -1 do              begin                lRotateTimeline.SetFrame(lFrameIndex, Self.ReadFloat(AStream), Self.ReadFloat(AStream));                if lFrameIndex < lFrameCount - 1 then 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);                else                begin                  lTranslateTimeline:= TTranslateTimeline.Create(lFrameCount);                  lTimelineScale:= Self.Scale;                end;              end;              lTranslateTimeline.BoneIndex:= lIndex;              for lFrameIndex:= 0 to lFrameCount -1 do              begin                lTranslateTimeline.SetFrame(lFrameIndex, Self.ReadFloat(AStream),                  Self.ReadFloat(AStream) * lTimelineScale, Self.ReadFloat(AStream) * lTimelineScale);                if lFrameIndex < lFrameCount - 1 then 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:= 0 to n -1 do    begin      lIndex:= Self.ReadVarInt(AStream, True);        //IkConstraintIndex      lFrameCount:= Self.ReadVarInt(AStream, True);      lIkConstraintTimeline:= TIkConstraintTimeline.Create(lFrameCount);      lIkConstraintTimeline.IkConstraintIndex:= lIndex;      for lFrameIndex:= 0 to lFrameCount -1 do      begin        lIkConstraintTimeline.SetFrame(lFrameIndex, Self.ReadFloat(AStream),          Self.ReadFloat(AStream), Self.ReadSByte(AStream));        if lFrameIndex < lFrameCount - 1 then 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:= 0 to n -1 do    begin      lIndex:= Self.ReadVarInt(AStream, True);          //TransformConstraintIndex      lFrameCount:= Self.ReadVarInt(AStream, True);      lTransformConstraintTimeline:= TTransformConstraintTimeline.Create(lFrameCount);      lTransformConstraintTimeline.TransformConstraintIndex:= lIndex;      for lFrameIndex:= 0 to lFrameCount -1 do      begin        lTransformConstraintTimeline.SetFrame(lFrameIndex, Self.ReadFloat(AStream),          Self.ReadFloat(AStream), Self.ReadFloat(AStream), Self.ReadFloat(AStream), Self.ReadFloat(AStream));        if lFrameIndex < lFrameCount - 1 then 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:= 0 to n -1 do    begin      lIndex:= Self.ReadVarInt(AStream, True);         //PathConstraintIndex      lPathConstraintData:= ASkeletonData.PathConstraintDatas.Items[lIndex];      nn:= Self.ReadVarInt(AStream, True);      for j:= 0 to nn -1 do      begin        lTimelineType:= Self.ReadSByte(AStream);        lFrameCount:= Self.ReadVarInt(AStream, True);        case lTimelineType of          PATH_POSITION, PATH_SPACING:            begin              lTimelineScale:= 1;              if lTimelineType = PATH_SPACING then              begin                lPathConstraintPositionTimeline:= TPathConstraintSpacingTimeline.Create(lFrameCount);                if (lPathConstraintData.SpacingMode = TSpacingMode.smLength) or                   (lPathConstraintData.SpacingMode = TSpacingMode.smFixed) then                  lTimelineScale:= Self.Scale;              end else              begin                lPathConstraintPositionTimeline:= TPathConstraintPositionTimeline.Create(lFrameCount);                if lPathConstraintData.PositionMode = TPositionMode.pmFixed then                  lTimelineScale:= Self.Scale;              end;              lPathConstraintPositionTimeline.PathConstraintIndex:= lIndex;              for lFrameIndex:= 0 to lFrameCount -1 do              begin                lPathConstraintPositionTimeline.SetFrame(lFrameIndex, Self.ReadFloat(AStream), Self.ReadFloat(AStream) * lTimelineScale);                if lFrameIndex < lFrameCount - 1 then 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:= 0 to lFrameCount -1 do              begin                lPathConstraintMixTimeline.SetFrame(lFrameIndex, Self.ReadFloat(AStream),                  Self.ReadFloat(AStream), Self.ReadFloat(AStream));                if lFrameIndex < lFrameCount - 1 then 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:= 0 to n -1 do    begin      lSkin:= ASkeletonData.Skins.Items[Self.ReadVarInt(AStream, True)];      nn:= Self.ReadVarInt(AStream, True);      for j:= 0 to nn -1 do      begin        lIndex:= Self.ReadVarInt(AStream, True);         //slotindex        nnn:= Self.ReadVarInt(AStream, True);        for k:= 0 to nnn -1 do        begin          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:= 0 to lFrameCount -1 do          begin            lTime:= Self.ReadFloat(AStream);            lEnd:= Self.ReadVarInt(AStream, True);            if lEnd = 0 then            begin              if lWeighted then                SetLength(lDeform, lDeformLength)              else                lDeform:= lVertexAttachment.Vertices;            end else            begin              SetLength(lDeform, lDeformLength);              lStart:= Self.ReadVarInt(AStream, True);              lEnd:= lEnd + lStart;              if Self.Scale = 1 then              begin                for v:= lStart to lEnd -1 do                  lDeform[v]:= Self.ReadFloat(AStream);              end else              begin                for v:= lStart to lEnd -1 do                  lDeform[v]:= Self.ReadFloat(AStream) * Self.Scale;              end;              if not lWeighted then                for v:= 0 to Length(lDeform) -1 do                  lDeform[v]:= lDeform[v] + lVertexAttachment.Vertices[v];            end;            lDeformTiemline.SetFrame(lFrameIndex, lTime, lDeform);            if lFrameIndex < lFrameCount -1 then 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); //drawOrderCount    if n > 0 then    begin      lDrawOrderTimeline:= TDrawOrderTimeline.Create(n);      lSlotCount:= ASkeletonData.SlotDatas.Count;      for i:= 0 to n -1 do      begin        lTime:= Self.ReadFloat(AStream);        lOffsetCount:= Self.ReadVarInt(AStream, True);        SetLength(lDrawOrder, lSlotCount);        for j:= lSlotCount -1 downto 0 do          lDrawOrder[j]:= -1;        SetLength(lUnChanged, lSlotCount - lOffsetCount);        lOriginalIndex:= 0;        lUnChangedIndex:= 0;        for j:= 0 to lOffsetCount -1 do        begin          lIndex:= Self.ReadVarInt(AStream, True); //slotindex          // Collect unchanged items.          while lOriginalIndex <> lIndex do          begin            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 do        begin          lUnChanged[lUnChangedIndex]:= lOriginalIndex;          Inc(lUnChangedIndex);          Inc(lOriginalIndex);        end;        // Fill in unchanged items.        for j:= lSlotCount downto 0 do        begin          if lDrawOrder[j] = -1 then          begin            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); //eventCount    if n > 0 then    begin      lEventTimeline:= TEventTimeline.Create(n);      for i:= 0 to n -1 do      begin        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);begin  case 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 = -1 then raise 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) shl 24;  result:= result + (Self.ReadByte(AStream) shl 16);  result:= result + (Self.ReadByte(AStream) shl 8);  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) <> 0 then  begin    lByte:= Self.ReadByte(AStream);    result:= result or ((lByte and $7F) shl 7);    if (lByte and $80) <> 0 then    begin      lByte:= Self.ReadByte(AStream);      result:= result or ((lByte and $7F) shl 14);      if (lByte and $80) <> 0 then      begin        lByte:= Self.ReadByte(AStream);        result:= result or ((lByte and $7F) shl 21);        if (lByte and $80) <> 0 then          result:= result or ((lByte and $7F) shl 28);      end;    end;  end;  //  if not AOptimizePositive then    result:= (((Result shr 1) and $7fffffff) xor -(Result and 1));end;function TSpineSkeletonBinary.ReadString(const AStream: TStream): string;var  lByteCount: Integer;  lBuffer: TArray<Byte>;begin  lByteCount:= Self.ReadVarInt(AStream, True);  case lByteCount of    0, 1: exit('');    else      begin        lByteCount:= lByteCount - 1;        if Length(lBuffer) < lByteCount then          SetLength(lBuffer, lByteCount)        else          TArray.Copy<Byte>(FBuffer, lBuffer, 0, 0, Length(FBuffer));        TSpineSkeletonBinary.ReadFully(AStream, lBuffer, 0, lByteCount);        result:= System.SysUtils.StringOf(lBuffer);      end;  end;end;class procedure TSpineSkeletonBinary.ReadFully(const AStream: TStream;  var ABuffer: TArray<Byte>; const AOffset: Integer; var ALength: Integer);var  lOffset, lCount: Integer;begin  lOffset:= AOffset;  while ALength > 0 do  begin    lCount:= AStream.Read(ABuffer, lOffset, ALength);    if lCount <= 0 then raise 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

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

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

最新文章

123

最新摄影

微信扫一扫

第七城市微信公众平台