本篇文章主要介绍了" Spine Runtime for Delphi移植笔记(七) - spinecoreskeleton",主要涉及到方面的内容,对于Delphijrs看球网直播吧_低调看直播体育app软件下载_低调看体育直播感兴趣的同学可以参考一下:
////////////////////////////////////////////////////////////////////////////////...
////////////////////////////////////////////////////////////////////////////////
//Generic delphi runtime v3.6 for Spine animation tool //
//Runtime port by cjk (hzi1980@163.com) //
////////////////////////////////////////////////////////////////////////////////unit spine.core.skeleton;
interfaceuses
System.Classes, System.SysUtils, System.Generics.Collections, System.Math,
spine.types, spine.classes, spine.data,
spine.core.bone, spine.core.slot, spine.core.skin, spine.core.attachment, spine.core.constraint;
type
TSpineSkeleton = class(ISkeleton)
private
FPathConstraints: TObjectList;
FIkConstraints: TObjectList;
FTransformConstraints: TObjectList;
FBones: TObjectList;
FSlots: TObjectList;
FDrawOrder: TList;
FUpdateCacheList: TList;
FData: TSkeletonData;
FUpdateCacheReset: TList;
function GetRootBone: TSpineBone;
privateprocedure SortIkConstraint(const AConstraint: TIkConstraint);
procedure SortPathConstraint(const AConstraint: TPathConstraint);
procedure SortTransformConstraint(const AConstraint: TTransformConstraint);
procedure SortPathConstraintAttachment(const ASkin: TSpineSkin;
const ASlotIndex: Integer; const ASlotBone: TSpineBone); overload;
procedure SortPathConstraintAttachment(const AAttachment: IAttachment;
const ASlotBone: TSpineBone); overload;
procedure SortBone(const ABone: TSpineBone);
procedure SortReset(const ABones: TObjectList);
public
Skin: TSpineSkin;
R, G, B, A: Single;
Time: Single;
X, Y: Single;
FlipX, FlipY: Boolean;
property Data: TSkeletonData read FData;
property Bones: TObjectList read FBones;
property UpdateCacheList: TList read FUpdateCacheList;
property Slots: TObjectList read FSlots;
property DrawOrder: TList read FDrawOrder;
property IkConstraints: TObjectList read FIkConstraints;
property PathConstraints: TObjectList read FPathConstraints;
property TransformConstraints: TObjectList read FTransformConstraints;
property RootBone: TSpineBone read GetRootBone;
publicconstructorCreate(const AData: TSkeletonData);
destructorDestroy; override;
procedure UpdateCache;
procedure UpdateWorldTransform;
procedure SetToSetupPose;
procedure SetBonesToSetupPose;
procedure SetSlotsToSetupPose;
procedure SetSkin(const ASkinName: string); overload;
procedure SetSkin(const ASkin: TSpineSkin); overload;
procedure SetAttachment(const ASlotName, AAttachmentName: string);
procedure Update(const ADelta: Single);
procedure GetBounds(out oX, oY, oWidth, oHeight: Single; var AVertexBuffer: TArray);
function GetAttachment(const ASlotName, AAttachmentName: string): IAttachment; overload;
function GetAttachment(const ASlotIndex: Integer; const AAttachmentName: string): IAttachment; overload;
function FindBone(const ABoneName: string): TSpineBone;
function FindBoneIndex(const ABoneName: string): Integer;
function FindSlot(const ASlotName: string): TSpineSlot;
function FindSlotIndex(const ASlotName: string): Integer;
function FindIkConstraint(const AConstraintName: string): TIkConstraint;
function FindTransformConstraint(const AConstraintName: string): TTransformConstraint;
function FindPathConstraint(const AConstraintName: string): TPathConstraint;
end;
implementation{ TSpineSkeleton }function TSpineSkeleton.GetRootBone: TSpineBone;
begin
result:= nil;
if FBones.Count > 0then
result:= FBones.Items[0];
end;
constructor TSpineSkeleton.Create(const AData: TSkeletonData);
var
lBoneData: TBoneData;
lParentBone, lBone: TSpineBone;
lSlotData: TSlotData;
lSlot: TSpineSlot;
lIkData : TIkConstraintData;
lTfData : TTransformConstraintData;
lPathData: TPathConstraintData;
begininheritedCreate;
R:= 1; G:= 1; B:= 1; A:= 1;
FUpdateCacheList:= TList.Create;
FUpdateCacheReset:= TList.Create;
FDrawOrder:= TList.Create;
FBones:= TObjectList.Create;
FSlots:= TObjectList.Create;
FIkConstraints:= TObjectList.Create;
FPathConstraints:= TObjectList.Create;
FTransformConstraints:= TObjectList.Create;
ifnot Assigned(AData) thenraise Exception.Create('data cannot be null.');
FData:= AData;
for lBoneData in FData.BoneDatas dobeginifnot Assigned(lBoneData.Parent) then
FBones.Add(TSpineBone.Create(lBoneData, Self, nil))
elsebegin
lParentBone:= FBones.Items[lBoneData.Parent.Index];
lBone:= TSpineBone.Create(lBoneData, Self, lParentBone);
FBones.Add(lBone);
end;
end;
for lSlotData in FData.SlotDatas dobegin
lBone:= FBones.Items[lSlotData.BoneData.Index];
lSlot:= TSpineSlot.Create(lSlotData, lBone);
FSlots.Add(lSlot);
FDrawOrder.Add(lSlot);
end;
for lIkData in FData.IkConstraintDatas do
FIkConstraints.Add(TIkConstraint.Create(lIkData, Self));
for lTfData in FData.TransformConstraintDatas do
FTransformConstraints.Add(TTransformConstraint.Create(lTfData, Self));
for lPathData in FData.PathConstraintDatas do
FPathConstraints.Add(TPathConstraint.Create(lPathData, Self));
//
UpdateCache();
UpdateWorldTransform();
end;
destructor TSpineSkeleton.Destroy;
begin
FUpdateCacheReset.Free;
FBones.Free;
FUpdateCacheList.Free;
FSlots.Free;
FDrawOrder.Free;
FIkConstraints.Free;
FPathConstraints.Free;
FTransformConstraints.Free;
inherited;
end;
procedure TSpineSkeleton.UpdateCache;
var
i, lConstraintCount, j: Integer;
lFound: Boolean;
begin
FUpdateCacheList.Clear;
FUpdateCacheReset.Clear;
for i:= 0to FBones.Count -1do
FBones.Items[i].Sorted:= False;
lConstraintCount:= FIkConstraints.Count +
FTransformConstraints.Count +
FPathConstraints.Count;
lFound:= False;
for i:= 0to lConstraintCount -1dobeginfor j:= 0to FIkConstraints.Count -1dobeginif FIkConstraints[j].Data.Order = j thenbegin
SortIkConstraint(FIkConstraints[j]);
lFound:= True;
break;
end;
end;
ifnot lFound thenbeginfor j:= 0to FTransformConstraints.Count -1dobeginif FTransformConstraints[j].Data.Order = j thenbegin
SortTransformConstraint(FTransformConstraints[j]);
lFound:= True;
break;
end;
end;
end;
ifnot lFound thenbeginfor j:= 0to FPathConstraints.Count -1dobeginif FPathConstraints[j].Data.Order = j thenbegin
SortPathConstraint(FPathConstraints[j]);
lFound:= True;
break;
end;
end;
end;
end;
//
for i:= 0to FBones.Count -1do
SortBone(FBones.Items[i]);
end;
procedure TSpineSkeleton.SortIkConstraint(const AConstraint: TIkConstraint);
var
lChild: TSpineBone;
begin
SortBone(AConstraint.Target);
SortBone(AConstraint.Bones.Items[0]);
if AConstraint.Bones.Count > 1thenbegin
lChild:= AConstraint.Bones.Last;
ifnot FUpdateCacheList.Contains(lChild) then
FUpdateCacheReset.Add(lChild);
end;
FUpdateCacheList.Add(AConstraint);
SortReset(AConstraint.Bones.Items[0].Children);
AConstraint.Bones.Last.Sorted:= True;
end;
procedure TSpineSkeleton.SortPathConstraint(const AConstraint: TPathConstraint);
var
lSlot: TSpineSlot;
lSlotIndex, i: Integer;
lSlotBone: TSpineBone;
begin
lSlot:= AConstraint.Target;
lSlotIndex:= lSlot.Data.Index;
lSlotBone := lSlot.Bone;
if Assigned(Skin) then
SortPathConstraintAttachment(Skin, lSlotIndex, lSlotBone);
if Assigned(FData.DefaultSkin) andnot FData.DefaultSkin.Equals(Skin) then
SortPathConstraintAttachment(FData.DefaultSkin, lSlotIndex, lSlotBone);
for i:= 0to FData.Skins.Count -1do
SortPathConstraintAttachment(FData.Skins.Items[i], lSlotIndex, lSlotBone);
if (lSlot.Attachment is TPathAttachment) then
SortPathConstraintAttachment(lSlot.Attachment, lSlotBone);
for i:= 0to AConstraint.Bones.Count -1do
SortBone(AConstraint.Bones.Items[i]);
//
FUpdateCacheList.Add(AConstraint);
for i:= 0to AConstraint.Bones.Count -1do
SortReset(AConstraint.Bones.Items[i].Children);
for i:= 0to AConstraint.Bones.Count -1do
AConstraint.Bones.Items[i].Sorted:= True;
end;
procedure TSpineSkeleton.SortTransformConstraint(const AConstraint: TTransformConstraint);
var
i: Integer;
lChild: TSpineBone;
begin
SortBone(AConstraint.Target);
if AConstraint.Data.Local thenbeginfor i:= 0to AConstraint.Bones.Count -1dobegin
lChild:= AConstraint.Bones.Items[i];
SortBone(lChild.Parent);
ifnot FUpdateCacheList.Contains(lChild) then
FUpdateCacheReset.Add(lChild);
end;
endelsebeginfor i:= 0to AConstraint.Bones.Count -1do
SortBone(AConstraint.Bones.Items[i]);
end;
FUpdateCacheList.Add(AConstraint);
for i:= 0to AConstraint.Bones.Count -1do
SortReset(AConstraint.Bones.Items[i].Children);
for i:= 0to AConstraint.Bones.Count -1do
AConstraint.Bones.Items[i].Sorted:= True;
end;
procedure TSpineSkeleton.SortPathConstraintAttachment(const ASkin: TSpineSkin;
const ASlotIndex: Integer; const ASlotBone: TSpineBone);
var
lPair: TPair;
beginfor lPair in Skin.Attachments dobeginif lPair.Key.SlotIndex = ASlotIndex then
SortPathConstraintAttachment(lPair.Value, ASlotBone);
end;
end;
procedure TSpineSkeleton.SortPathConstraintAttachment(
const AAttachment: IAttachment; const ASlotBone: TSpineBone);
var
lPathBones: TArray;
i, n, nn, boneCount: Integer;
beginifnot (AAttachment is TPathAttachment) then exit;
//
lPathBones:= TPathAttachment(AAttachment).Bones;
if Length(lPathBones) = 0then
SortBone(ASlotBone)
elsebegin
i:= 0;
n:= Length(lPathBones);
while i < n dobegin
boneCount:= lPathBones[i + 1];
i:= i + 1;
nn:= i + boneCount;
while i < nn dobegin
SortBone(FBones.Items[lPathBones[i + 1]]);
i:= i + 1;
endend;
end;
end;
procedure TSpineSkeleton.SortBone(const ABone: TSpineBone);
beginif ABone.Sorted then exit;
//
if Assigned(ABone.Parent) then
SortBone(ABone.Parent);
ABone.Sorted:= True;
FUpdateCacheList.Add(ABone);
end;
procedure TSpineSkeleton.SortReset(const ABones: TObjectList);
var
i: Integer;
lBone: TSpineBone;
beginfor i:= 0to ABones.Count -1dobegin
lBone:= ABones.Items[i];
if lBone.Sorted then
SortReset(lBone.Children);
lBone.Sorted:= False;
end;
end;
procedure TSpineSkeleton.UpdateWorldTransform;
var
i: Integer;
lBone: TSpineBone;
beginfor i:= 0to FUpdateCacheReset.Count -1dobegin
lBone:= FUpdateCacheReset.Items[i];
lBone.AppliedX:= lBone.X;
lBone.AppliedY:= lBone.Y;
lBone.AppliedRotation:= lBone.Rotation;
lBone.AppliedScaleX:= lBone.ScaleX;
lBone.AppliedScaleY:= lBone.ScaleY;
lBone.AppliedShearX:= lBone.ShearX;
lBone.AppliedShearY:= lBone.ShearY;
lBone.AppliedValid:= True;
end;
for i:= 0to FUpdateCacheList.Count -1do
FUpdateCacheList.Items[i].Update;
end;
procedure TSpineSkeleton.SetToSetupPose;
begin
SetBonesToSetupPose();
SetSlotsToSetupPose();
end;
procedure TSpineSkeleton.SetBonesToSetupPose;
var
i: Integer;
beginfor i:= 0to FBones.Count -1do
FBones.Items[i].SetToSetupPose;
for i:= 0to FIkConstraints.Count -1dobeginwith FIkConstraints.Items[i] dobegin
BendDirection:= Data.BendDirection;
Mix:= Data.Mix;
end;
end;
for i:= 0to FTransformConstraints.Count -1dobeginwith FTransformConstraints.Items[i] dobegin
RotateMix:= Data.RotateMix;
TranslateMix:= Data.TranslateMix;
ScaleMix:= Data.ScaleMix;
ShearMix:= Data.ShearMix;
end;
end;
for i:= 0to FPathConstraints.Count -1dobeginwith FPathConstraints.Items[i] dobegin
Position:= Data.Position;
Spacing:= Data.Spacing;
RotateMix:= Data.RotateMix;
TranslateMix:= Data.TranslateMix;
end;
end;
end;
procedure TSpineSkeleton.SetSlotsToSetupPose;
var
i: Integer;
begin
FDrawOrder.Clear;
for i:= 0to FSlots.Count -1do
FDrawOrder.Add(FSlots.Items[i]);
for i:= 0to FSlots.Count -1do
FSlots.Items[i].SetToSetupPose;
end;
function TSpineSkeleton.FindBone(const ABoneName: string): TSpineBone;
var
i: Integer;
beginif ABoneName.Trim.IsEmpty thenraise Exception.Create('boneName cannot be null.');
for i:= 0to FBones.Count -1dobeginif FBones.Items[i].Data.Name = ABoneName then
exit(FBones.Items[i]);
end;
result:= nil;
end;
function TSpineSkeleton.FindBoneIndex(const ABoneName: string): Integer;
var
i: Integer;
begin
result:= -1;
if ABoneName.Trim.IsEmpty thenraise Exception.Create('boneName cannot be null.');
for i:= 0to FBones.Count -1dobeginif FBones.Items[i].Data.Name = ABoneName then
exit(i);
end;
end;
function TSpineSkeleton.FindSlot(const ASlotName: string): TSpineSlot;
var
i: Integer;
begin
result:= nil;
if ASlotName.Trim.IsEmpty thenraise Exception.Create('slotName cannot be null.');
for i:= 0to FSlots.Count -1dobeginif FSlots.Items[i].Data.Name = ASlotName then
exit(FSlots.Items[i]);
end;
end;
function TSpineSkeleton.FindSlotIndex(const ASlotName: string): Integer;
var
i: Integer;
begin
result:= -1;
if ASlotName.Trim.IsEmpty thenraise Exception.Create('slotName cannot be null.');
for i:= 0to FSlots.Count -1dobeginif FSlots.Items[i].Data.Name = ASlotName then
exit(i);
end;
end;
procedure TSpineSkeleton.SetSkin(const ASkinName: string);
var
lSkin: TSpineSkin;
begin
lSkin:= FData.FindSkin(ASkinName);
ifnot Assigned(lSkin) thenraise Exception.CreateFmt('Skin not found: %s',[ASkinName]);
SetSkin(lSkin);
end;
procedure TSpineSkeleton.SetSkin(const ASkin: TSpineSkin);
var
i: Integer;
lAttachmentName: string;
lAttachment: IAttachment;
beginif Assigned(Self.Skin) then
ASkin.AttachAll(Self, Self.Skin)
elsebeginfor i:= 0to FSlots.Count -1dobegin
lAttachmentName:= FSlots.Items[i].Data.AttachmentName;
ifnot lAttachmentName.Trim.IsEmpty thenbegin
lAttachment:= ASkin.GetAttachment(i, lAttachmentName);
if Assigned(lAttachment) then
FSlots.Items[i].Attachment:= lAttachment;
end;
end;
end;
Self.Skin:= ASkin;
end;
function TSpineSkeleton.GetAttachment(const ASlotName,
AAttachmentName: string): IAttachment;
begin
result:= GetAttachment(FData.FindSlotIndex(ASlotName), AAttachmentName);
end;
function TSpineSkeleton.GetAttachment(const ASlotIndex: Integer;
const AAttachmentName: string): IAttachment;
var
lAttachment: IAttachment;
begin
result:= nil;
if AAttachmentName.Trim.IsEmpty thenraise Exception.Create('attachmentName cannot be null.');
if Assigned(Self.Skin) thenbegin
lAttachment:= Self.Skin.GetAttachment(ASlotIndex, AAttachmentName);
if Assigned(lAttachment) then exit(lAttachment);
end;
if Assigned(FData.DefaultSkin) then
result:= FData.DefaultSkin.GetAttachment(ASlotIndex, AAttachmentName);
end;
procedure TSpineSkeleton.SetAttachment(const ASlotName,
AAttachmentName: string);
var
i: Integer;
lSlot: TSpineSlot;
lAttachment: IAttachment;
beginif ASlotName.Trim.IsEmpty thenraise Exception.Create('slotName cannot be null.');
for i:= 0to FSlots.Count -1dobegin
lSlot:= FSlots.Items[i];
if lSlot.Data.Name.Equals(ASlotName) thenbegin
lAttachment:= nil;
ifnot AAttachmentName.Trim.IsEmpty thenbegin
lAttachment:= Self.GetAttachment(i, AAttachmentName);
ifnot Assigned(lAttachment) thenraise Exception.CreateFmt('Attachment not found: %s, for slot: %s',[AAttachmentName,ASlotName]);
end;
lSlot.Attachment:= lAttachment;
exit;
end;
end;
raise Exception.CreateFmt('Slot not found: ',[ASlotName]);
end;
function TSpineSkeleton.FindIkConstraint(
const AConstraintName: string): TIkConstraint;
var
i: Integer;
lConstraint: TIkConstraint;
begin
result:= nil;
if AConstraintName.Trim.IsEmpty thenraise Exception.Create('constraintName cannot be null.');
for i:= 0to FIkConstraints.Count -1dobegin
lConstraint:= FIkConstraints.Items[i];
if lConstraint.Data.Name.Equals(AConstraintName) then exit(lConstraint);
end;
end;
function TSpineSkeleton.FindTransformConstraint(
const AConstraintName: string): TTransformConstraint;
var
i: Integer;
lConstraint: TTransformConstraint;
begin
result:= nil;
if AConstraintName.Trim.IsEmpty thenraise Exception.Create('constraintName cannot be null.');
for i:= 0to FTransformConstraints.Count -1dobegin
lConstraint:= FTransformConstraints.Items[i];
if lConstraint.Data.Name.Equals(AConstraintName) then exit(lConstraint);
end;
end;
function TSpineSkeleton.FindPathConstraint(
const AConstraintName: string): TPathConstraint;
var
i: Integer;
lConstraint: TPathConstraint;
begin
result:= nil;
if AConstraintName.Trim.IsEmpty thenraise Exception.Create('constraintName cannot be null.');
for i:= 0to FPathConstraints.Count -1dobegin
lConstraint:= FPathConstraints.Items[i];
if lConstraint.Data.Name.Equals(AConstraintName) then exit(lConstraint);
end;
end;
procedure TSpineSkeleton.Update(const ADelta: Single);
begin
Self.Time:= Self.Time + ADelta;
end;
procedure TSpineSkeleton.GetBounds(out oX, oY, oWidth, oHeight: Single;
var AVertexBuffer: TArray);
var
lTemp, lVertices: TArray;
i, lVerticesLength, j, n: Integer;
lMinX, lMinY, lMaxX, lMaxY, lVX, lVY: Single;
lSlot: TSpineSlot;
lAttachment: IAttachment;
lRegionAttachment: TRegionAttachment;
lMeshAttachment: TMeshAttachment;
begin
lTemp:= AVertexBuffer;
if Length(lTemp) = 0then
SetLength(lTemp, 8);
lMinX:= Integer.MaxValue;
lMinY:= Integer.MaxValue;
lMaxX:= Integer.MinValue;
lMaxY:= Integer.MinValue;
for i:= 0to FDrawOrder.Count -1dobegin
lSlot:= FDrawOrder.Items[i];
lVerticesLength:= 0;
SetLength(lVertices, 0);
lAttachment:= lSlot.Attachment;
lRegionAttachment:= lAttachment as TRegionAttachment;
if Assigned(lRegionAttachment) thenbegin
lVerticesLength:= 8;
lVertices:= lTemp;
if Length(lVertices) < 8thenbegin
SetLength(lTemp, 8);
lVertices:= lTemp;
lRegionAttachment.ComputeWorldVertices(lSlot.Bone, lTemp, 0);
end;
endelsebegin
lMeshAttachment:= lAttachment as TMeshAttachment;
if Assigned(lMeshAttachment) thenbegin
lVerticesLength:= lMeshAttachment.WorldVerticesLength;
lVertices:= lTemp;
if Length(lVertices) < lVerticesLength thenbegin
SetLength(lTemp, lVerticesLength);
lVertices:= lTemp;
lMeshAttachment.ComputeWorldVertices(lSlot, 0, lVerticesLength, lTemp, 0);
end;
end;
end;
n:= Length(lVertices);
if n > 0thenbegin
j:= 0;
while j < n dobegin
lVX:= lVertices[j];
lVY:= lVertices[j+1];
lMinX:= Min(lMinX, lVX);
lMinY:= Min(lMinY, lVY);
lMaxX:= Max(lMaxX, lVX);
lMaxY:= Max(lMaxY, lVY);
j:= j + 2;
end;
end;
end;
oX:= lMinX;
oY:= lMinY;
oWidth := lMaxX - lMinX;
oHeight:= lMaxY - lMinY;
AVertexBuffer:= lTemp;
end;
end.
骨架模块,粗粗检查了一下,没什么问题。