【Spine】Spine Runtime for Delphi移植笔记(八) - spine.data

////////////////////////////////////////////////////////////////////////////////
//Generic delphi runtime v3.6 for Spine animation tool                        //
//Runtime port by cjk (hzi1980@163.com)                                       //
////////////////////////////////////////////////////////////////////////////////

unit spine.data;

interface

uses
  System.Classes, System.SysUtils, System.Generics.Collections,
  spine.types, spine.classes,
  spine.core.skin, spine.core.animation;

type
  TSkeletonData = class;
  TBoneData = class;
  TSlotData = class;
  TEventData = class;
  TAnimationStateData = class;
  TIkConstraintData = class;
  TTransformConstraintData = class;
  TPathConstraintData = class;

  TSkeletonData = class(TObject)
  private
    FPathConstraintDatas: TObjectList<TPathConstraintData>;
    FIkConstraintDatas: TObjectList<TIkConstraintData>;
    FTransformConstraintDatas: TObjectList<TTransformConstraintData>;
    FEventDatas: TObjectList<TEventData>;
    FBoneDatas: TObjectList<TBoneData>;
    FSkins: TObjectList<TSpineSkin>;
    FSlotDatas: TObjectList<TSlotData>;
    FAnimations: TObjectList<TSpineAnimation>;
  public
    Name: string;
    DefaultSkin: TSpineSkin;
    Width, Height: Single;
    Version: string;
    Hash: string;
    ImagesPath: string;
    FPS: Single;
    property BoneDatas: TObjectList<TBoneData> read FBoneDatas;
    property SlotDatas: TObjectList<TSlotData> read FSlotDatas;
    property Skins: TObjectList<TSpineSkin> read FSkins;
    property EventDatas: TObjectList<TEventData> read FEventDatas;
    property Animations: TObjectList<TSpineAnimation> read FAnimations;
    property IkConstraintDatas: TObjectList<TIkConstraintData> read FIkConstraintDatas;
    property TransformConstraintDatas: TObjectList<TTransformConstraintData> read FTransformConstraintDatas;
    property PathConstraintDatas: TObjectList<TPathConstraintData> read FPathConstraintDatas;
  public
    constructor Create;
    destructor Destroy; override;

    function FindBone(const ABoneDataName: string): TBoneData;
    function FindBoneIndex(const ABoneDataName: string): Integer;
    function FindSlot(const ASlotDataName: string): TSlotData;
    function FindSlotIndex(const ASlotDataName: string): Integer;
    function FindSkin(const ASkinName: string): TSpineSkin;
    function FintEvent(const AEventDataName: string): TEventData;
    function FindAnimation(const AAnimationName: string): TSpineAnimation;
    function FindIkConstraint(const AConstraintDataName: string): TIkConstraintData;
    function FindTransformConstraint(const AConstraintDataName: string): TTransformConstraintData;
    function FindPathConstraint(const AConstraintDataName: string): TPathConstraintData;
    function FindPathConstraintIndex(const AConstraintDataName: string): Integer;
  end;

  TBoneData = class(TObject)
  private
    FIndex: Integer;
    FName: string;
    FParent: TBoneData;
  public
    Length: Single;
    X, Y, Rotation, ScaleX, ScaleY, ShearX, ShearY: Single;
    TransformMode: TTransformMode;
    property Index: Integer read FIndex;
    property Name: string read FName;
    property Parent: TBoneData read FParent;
  public
    constructor Create(const AIndex: Integer; const AName: string; const AParent: TBoneData);
  end;

  TSlotData = class(TObject)
  private
    FIndex: Integer;
    FName: string;
    FBoneData: TBoneData;
  public
    R, G, B, A, R2, G2, B2: Single;
    HasSecondColor: Boolean;
    AttachmentName: string;
    BlendMode: TBlendMode;
    property Index: Integer read FIndex;
    property Name: string read FName;
    property BoneData: TBoneData read FBoneData;
  public
    constructor Create(const AIndex: Integer; const AName: string; const ABoneData: TBoneData);
  end;

  TEventData = class(TObject)
  private
    FName: string;
  public
    IntValue: Integer;
    FloatValue: Single;
    StringValue: string;
    property Name: string read FName;
  public
    constructor Create(const AName: string);
  end;

  TAnimationPair = record
    A1: TSpineAnimation;
    A2: TSpineAnimation;
  end;
  TAnimationStateData = class(TObject)
  private
    FSkeletonData: TSkeletonData;
    FAnimationToMixTime: TDictionary<TAnimationPair, Single>;
  public
    DefaultMix: Single;
    property SkeletonData: TSkeletonData read FSkeletonData;
  public
    constructor Create(const ASkeletonData: TSkeletonData);
    destructor Destroy; override;

    procedure SetMix(const AFromName, AToName: string; const ADuration: Single); overload;
    procedure SetMix(const AFrom, ATo: TSpineAnimation; const ADuration: Single); overload;
    function GetMix(const AFrom, ATo: TSpineAnimation): Single;
  end;

  TIkConstraintData = class(TObject)
  private
    FName: string;
    FBoneDatas: TList<TBoneData>;
  public
    Order: Integer;
    Mix: Single;
    BendDirection: Integer;
    Target: TBoneData;
    property Name: string read FName;
    property BoneDatas: TList<TBoneData> read FBoneDatas;
  public
    constructor Create(const AName: string);
    destructor Destroy; override;
  end;

  TTransformConstraintData = class(TObject)
  private
    FName: string;
    FBoneDatas: TList<TBoneData>;
  public
    Order: Integer;
    Target: TBoneData;
    RotateMix, TranslateMix, ScaleMix, ShearMix: Single;
    OffsetRotation, OffsetX, OffsetY, OffsetScaleX, OffsetScaleY, OffsetShearY: Single;
    Relative, Local: Boolean;
    property Name: string read FName;
    property BoneDatas: TList<TBoneData> read FBoneDatas;
  public
    constructor Create(const AName: string);
    destructor Destroy; override;
  end;

  TPathConstraintData = class(TObject)
  private
    FName: string;
    FBoneDatas: TList<TBoneData>;
  public
    Order: Integer;
    Relative: Boolean;
    Local: Boolean;
    Target: TSlotData;
    PositionMode: TPositionMode;
    SpacingMode: TSpacingMode;
    RotateMode: TRotateMode;
    OffsetRotation, Position, Spacing, RotateMix, TranslateMix: Single;
    property Name: string read FName;
    property BoneDatas: TList<TBoneData> read FBoneDatas;
  public
    constructor Create(const AName: string);
    destructor Destroy; override;
  end;

implementation

{ TSkeletonData }

constructor TSkeletonData.Create;
begin
  inherited Create;
  FPathConstraintDatas:= TObjectList<TPathConstraintData>.Create;
  FIkConstraintDatas:= TObjectList<TIkConstraintData>.Create;
  FTransformConstraintDatas:= TObjectList<TTransformConstraintData>.Create;
  FEventDatas:= TObjectList<TEventData>.Create;
  FBoneDatas:= TObjectList<TBoneData>.Create;
  FSkins:= TObjectList<TSpineSkin>.Create;
  FSlotDatas:= TObjectList<TSlotData>.Create;
  FAnimations:= TObjectList<TSpineAnimation>.Create;
end;

destructor TSkeletonData.Destroy;
begin
  FPathConstraintDatas.Free;
  FIkConstraintDatas.Free;
  FTransformConstraintDatas.Free;
  FEventDatas.Free;
  FBoneDatas.Free;
  FSkins.Free;
  FSlotDatas.Free;
  FAnimations.Free;
  inherited;
end;

function TSkeletonData.FindBone(const ABoneDataName: string): TBoneData;
var
  i: Integer;
begin
  result:= nil;
  if ABoneDataName.Trim.IsEmpty then raise Exception.Create('boneDataName cannot be null.');
  for i:= 0 to FBoneDatas.Count -1 do
  begin
    if FBoneDatas.Items[i].Name = ABoneDataName then
      exit(FBoneDatas.Items[i]);
  end;
end;

function TSkeletonData.FindBoneIndex(const ABoneDataName: string): Integer;
var
  i: Integer;
begin
  result:= -1;
  if ABoneDataName.Trim.IsEmpty then raise Exception.Create('boneDataName cannot be null.');
  for i:= 0 to FBoneDatas.Count -1 do
  begin
    if FBoneDatas.Items[i].Name = ABoneDataName then
      exit(i);
  end;
end;

function TSkeletonData.FindSkin(const ASkinName: string): TSpineSkin;
var
  lSkin: TSpineSkin;
begin
  result:= nil;
  if ASkinName.Trim.IsEmpty then raise Exception.Create('skinName cannot be null.');
  for lSkin in FSkins do
    if lSkin.Name = ASkinName then
      exit(lSkin);
end;

function TSkeletonData.FindSlot(const ASlotDataName: string): TSlotData;
var
  i: Integer;
begin
  result:= nil;
  if ASlotDataName.Trim.IsEmpty then raise Exception.Create('slotDataName cannot be null.');
  for i:= 0 to FSlotDatas.Count -1 do
  begin
    if FSlotDatas.Items[i].Name = ASlotDataName then
      exit(FSlotDatas.Items[i]);
  end;
end;

function TSkeletonData.FindSlotIndex(const ASlotDataName: string): Integer;
var
  i: Integer;
begin
  result:= -1;
  if ASlotDataName.Trim.IsEmpty then raise Exception.Create('slotDataName cannot be null.');
  for i:= 0 to FSlotDatas.Count -1 do
  begin
    if FSlotDatas.Items[i].Name = ASlotDataName then
      exit(i);
  end;
end;

function TSkeletonData.FintEvent(const AEventDataName: string): TEventData;
var
  lData: TEventData;
begin
  result:= nil;
  if AEventDataName.Trim.IsEmpty then raise Exception.Create('eventDataName cannot be null.');
  for lData in FEventDatas do
    if lData.Name = AEventDataName then
      exit(lData);
end;

function TSkeletonData.FindAnimation(const AAnimationName: string): TSpineAnimation;
var
  i: Integer;
begin
  result:= nil;
  if AAnimationName.Trim.IsEmpty then raise Exception.Create('animationName cannot be null.');
  for i:= 0 to FAnimations.Count -1 do
  begin
    if FAnimations.Items[i].Name = AAnimationName then
      exit(FAnimations.Items[i]);
  end;
end;

function TSkeletonData.FindIkConstraint(
  const AConstraintDataName: string): TIkConstraintData;
var
  i: Integer;
begin
  result:= nil;
  if AConstraintDataName.Trim.IsEmpty then raise Exception.Create('constraintDataName cannot be null.');
  for i:= 0 to FIkConstraintDatas.Count -1 do
  begin
    if FIkConstraintDatas.Items[i].Name = AConstraintDataName then
      exit(FIkConstraintDatas.Items[i]);
  end;
end;

function TSkeletonData.FindPathConstraint(
  const AConstraintDataName: string): TPathConstraintData;
var
  i: Integer;
begin
  result:= nil;
  if AConstraintDataName.Trim.IsEmpty then raise Exception.Create('constraintDataName cannot be null.');
  for i:= 0 to FPathConstraintDatas.Count -1 do
  begin
    if FPathConstraintDatas.Items[i].Name = AConstraintDataName then
      exit(FPathConstraintDatas.Items[i]);
  end;
end;

function TSkeletonData.FindPathConstraintIndex(
  const AConstraintDataName: string): Integer;
var
  i: Integer;
begin
  result:= -1;
  if AConstraintDataName.Trim.IsEmpty then raise Exception.Create('constraintDataName cannot be null.');
  for i:= 0 to FIkConstraintDatas.Count -1 do
  begin
    if FIkConstraintDatas.Items[i].Name = AConstraintDataName then
      exit(i);
  end;
end;

function TSkeletonData.FindTransformConstraint(
  const AConstraintDataName: string): TTransformConstraintData;
var
  i: Integer;
begin
  result:= nil;
  if AConstraintDataName.Trim.IsEmpty then raise Exception.Create('constraintDataName cannot be null.');
  for i:= 0 to FTransformConstraintDatas.Count -1 do
  begin
    if FTransformConstraintDatas.Items[i].Name = AConstraintDataName then
      exit(FTransformConstraintDatas.Items[i]);
  end;
end;

{ TBoneData }

constructor TBoneData.Create(const AIndex: Integer; const AName: string;
  const AParent: TBoneData);
begin
  inherited Create;
  if AIndex < 0 then raise Exception.Create('index must be >= 0.');
  if AName.Trim.IsEmpty then raise Exception.Create('name cannot be null.');
  FIndex:= AIndex;
  FName:= AName;
  FParent:= AParent;
  ScaleX:= 1;
  ScaleY:= 1;
  TransformMode:= TTransformMode.tmNormal;
end;

{ TSlotData }

constructor TSlotData.Create(const AIndex: Integer; const AName: string;
  const ABoneData: TBoneData);
begin
  inherited Create;
  if AIndex < 0 then raise Exception.Create('index must be >= 0.');
  if AName.Trim.IsEmpty then raise Exception.Create('name cannot be null.');
  if not Assigned(ABoneData) then raise Exception.Create('boneData cannot be null.');
  FIndex:= AIndex;
  FName:= AName;
  FBoneData:= ABoneData;
  R:= 1; G:= 1; B:= 1; A:= 1;
  R2:= 0; G2:= 0; B2:= 0;
  HasSecondColor:= False;
end;

{ TEventData }

constructor TEventData.Create(const AName: string);
begin
  inherited Create;
  if AName.Trim.IsEmpty then raise Exception.Create('name cannot be null.');
  FName:= AName;
end;

{ TAnimationStateData }

constructor TAnimationStateData.Create(const ASkeletonData: TSkeletonData);
begin
  inherited Create;
  if not Assigned(ASkeletonData) then raise Exception.Create('skeletonData cannot be null.');
  FAnimationToMixTime:= TDictionary<TAnimationPair, Single>.Create;
    FSkeletonData:= ASkeletonData;
end;

destructor TAnimationStateData.Destroy;
begin
  FAnimationToMixTime.Free;
  inherited;
end;

procedure TAnimationStateData.SetMix(const AFromName, AToName: string;
  const ADuration: Single);
var
  lFrom, lTo: TSpineAnimation;
begin
  lFrom:= FSkeletonData.FindAnimation(AFromName);
  if not Assigned(lFrom) then raise Exception.CreateFmt('Animation not found: %s',[AFromName]);
  lTo:= FSkeletonData.FindAnimation(AToName);
  if not Assigned(lTo) then raise Exception.CreateFmt('Animation not found: %s',[AToName]);
  SetMix(lFrom, lTo, ADuration);
end;

procedure TAnimationStateData.SetMix(const AFrom, ATo: TSpineAnimation;
  const ADuration: Single);
var
  lKey: TAnimationPair;
begin
  if not Assigned(AFrom) then raise Exception.Create('from animation cannot be null.');
  if not Assigned(ATo) then raise Exception.Create('to animation cannot be null.');
    lKey.A1:= AFrom;
  lKey.A2:= ATo;
  FAnimationToMixTime.AddOrSetValue(lKey, ADuration);
end;

function TAnimationStateData.GetMix(const AFrom, ATo: TSpineAnimation): Single;
var
  lKey: TAnimationPair;
begin
  if not Assigned(AFrom) then raise Exception.Create('from animation cannot be null.');
  if not Assigned(ATo) then raise Exception.Create('to animation cannot be null.');
    lKey.A1:= AFrom;
  lKey.A2:= ATo;
  if not FAnimationToMixTime.TryGetValue(lKey, result) then
    result:= DefaultMix;
end;

{ TIkConstraintData }

constructor TIkConstraintData.Create(const AName: string);
begin
  inherited Create;
  if AName.Trim.IsEmpty then raise Exception.Create('name cannot be null.');
  FName:= AName;
  FBoneDatas:= TList<TBoneData>.Create;
end;

destructor TIkConstraintData.Destroy;
begin
  FBoneDatas.Free;
  inherited;
end;

{ TTransformConstraintData }

constructor TTransformConstraintData.Create(const AName: string);
begin
  inherited Create;
  if AName.Trim.IsEmpty then raise Exception.Create('name cannot be null.');
  FName:= AName;
  FBoneDatas:= TList<TBoneData>.Create;
end;

destructor TTransformConstraintData.Destroy;
begin
  FBoneDatas.Free;
  inherited;
end;

{ TPathConstraintData }

constructor TPathConstraintData.Create(const AName: string);
begin
  inherited Create;
  if AName.Trim.IsEmpty then raise Exception.Create('name cannot be null.');
  FName:= AName;
  FBoneDatas:= TList<TBoneData>.Create;
end;

destructor TPathConstraintData.Destroy;
begin
  FBoneDatas.Free;
  inherited;
end;

end.

各种数据

posted @ 2017-08-02 14:49 水中盗影 阅读(...) 评论(...) 编辑 收藏