C2Anim.pas
上传用户:yj_qiu
上传日期:2022-08-08
资源大小:23636k
文件大小:40k
源码类别:

游戏引擎

开发平台:

Delphi

  1. (*
  2.  @Abstract(CAST II Engine animation unit)
  3.  (C) 2006-2007 George "Mirage" Bakhtadze. <a href="http://www.casteng.com">www.casteng.com</a> <br>
  4.  The source code may be used under either MPL 1.1 or LGPL 2.1 license. See included license.txt file <br>
  5.  Created: Feb 27, 2007 <br>
  6.  Unit contains tesselator and item classes with animation support
  7. *)
  8. {$Include GDefines.inc}
  9. {$Include C2Defines.inc}
  10. unit C2Anim;
  11. interface
  12. uses
  13.   TextFile,
  14.   SysUtils,
  15.   BaseTypes, Basics, Base3D, Props, BaseClasses, Resources,
  16.   C2Types, C2VisItems, C2Visual, C2Res, CAST2;
  17. //const
  18.   // Maximum number of animations per skeleton
  19. //  MaxAnimations = 16;
  20. type
  21.   TAnimatedTesselator = class(C2VisItems.TMeshTesselator)
  22.   protected
  23.     FFrame1, FFrame2, FTotalFrames: Integer;
  24.     FFactor: Single;
  25.     procedure SetTotalFrames(const Value: Integer); virtual;
  26.     procedure Update; virtual; abstract;
  27.   public
  28.     destructor Destroy; override;
  29.     procedure Fill(AVerticesRes: TVerticesResource; AIndicesRes: TIndicesResource);
  30.     procedure SetFrames(Frame1, Frame2: Integer; Factor: Single); virtual;
  31.     property TotalFrames: Integer read FTotalFrames write SetTotalFrames;
  32.     property Frame1: Integer read FFrame1;
  33.     property Frame2: Integer read FFrame2;
  34.     property Factor: Single read FFactor;
  35.   end;
  36.   TMorphedTesselator = class(TAnimatedTesselator)
  37.   protected
  38.     FrameVertices, FrameIndices: array of Pointer;
  39.     procedure SetTotalFrames(const Value: Integer); override;
  40.     procedure Update; override;
  41.   end;
  42.   TAnimatedItem = class(TVisible)
  43.   protected
  44.     MeshValid: Boolean;                                       // True if mesh is in valid state (all frames are ready etc)
  45.     FTotalFrames: Integer;
  46.     FFrame: Single;
  47.     procedure SetTotalFrames(const Value: Integer); virtual;
  48.     procedure SetFrame(const Value: Single); virtual;
  49.   public
  50.     procedure OnSceneLoaded; override;
  51.     procedure AddProperties(const Result: Props.TProperties); override;
  52.     procedure SetProperties(Properties: Props.TProperties); override;
  53.     procedure SetFrames(Frame1, Frame2: Integer; Factor: Single); virtual;
  54.     property TotalFrames: Integer read FTotalFrames write SetTotalFrames;
  55.   end;
  56.   TMorphedItem = class(TAnimatedItem)
  57.   private
  58.     function GetFrameIndicesRes(Index: Integer): TIndicesResource;
  59.     function GetFrameVerticesRes(Index: Integer): TVerticesResource;
  60.   protected
  61.     procedure SetMesh; override;
  62.   public
  63.     function GetTesselatorClass: CTesselator; override;
  64.     procedure AddProperties(const Result: Props.TProperties); override;
  65.     procedure SetProperties(Properties: Props.TProperties); override;
  66.     property FrameVertices[Index: Integer]: TVerticesResource read GetFrameVerticesRes;
  67.     property FrameIndices[Index: Integer]:  TIndicesResource  read GetFrameIndicesRes;
  68.   end;
  69.   TAnimationRec = record
  70.     Timestamp: Cardinal;
  71.     Transform: TMatrix4s;
  72.   end;
  73.   TAnimTransform = TMatrix4s;
  74. (*  PAnimSkeletonElement = ^TAnimSkeletonElement;
  75.   TAnimSkeletonElement = record
  76.     Name: TShortName;
  77.     OrigTransform,
  78.     AnimTransform,
  79.     TotalTransform: TMatrix4s;
  80.     Next, ChildHead: PAnimSkeletonElement;
  81.     Animation: array of TAnimationRec;
  82.   end;
  83.   TAnimSkeletons = array[0..$FFFF] of TAnimSkeletonElement;*)
  84.   // Pointer to skeleton element type
  85.   PSkeletonElement = ^TSkeletonElement;
  86.   // Animation skeleton type
  87.   TSkeletonElement = record
  88.     Index: Integer;
  89.     Next, ChildHead: PSkeletonElement;
  90.   end;
  91.   // Animation skeleton resource. Stores bones hierarchy as well as all per-bone static data.
  92.   TSkeletonResource = class(TArrayResource)
  93.   private
  94.     HCounts, HIndices: array of Integer;
  95.     procedure FreeSkeleton(El: PSkeletonElement);
  96.   protected
  97.     // Internal bone counter
  98.     FTotalBones: Integer;
  99.     // Called by @Link(AddProperties) for each bone. Can be used to specify custom properties in descendant skeleton types.
  100.     procedure AddElementProperties(Element: PSkeletonElement; const Result: Props.TProperties; const Prefix: AnsiString); virtual;
  101.     // Called by @Link(SetProperties) for each bone. Can be used to handle custom properties in descendant skeleton types.
  102.     procedure SetElementProperties(Element: PSkeletonElement; Properties: Props.TProperties; const Prefix: AnsiString); virtual;
  103.     // Sets total number of bones
  104.     procedure SetTotalBones(ATotalBones: Integer);
  105.   public
  106.     // Bone hierarchy head
  107.     Head: PSkeletonElement;
  108.     // Offset transformations
  109.     OffsTransform: array of TAnimTransform;
  110.     // Bone names
  111.     ElementNames: array of TShortName;
  112.     destructor Destroy; override;
  113.     function GetElementSize: Integer; override;
  114.     procedure AddProperties(const Result: Props.TProperties); override;
  115.     procedure SetProperties(Properties: Props.TProperties); override;
  116.     // Scales the skeleton by the given amount
  117.     procedure DoScale(Amount: TVector3s);
  118.     // Rotates the skeleton by the given amount
  119.     procedure DoRotate(Amount: TVector3s);
  120.     // Creates and returns a new amination skeleton element
  121.     function NewSkeletonElement: PSkeletonElement;
  122.     // Total number of bones
  123.     property TotalBones: Integer read FTotalBones write SetTotalBones;
  124.   end;
  125.   // Base class for animation resources
  126.   TAnimationResource = class(TArrayResource)
  127.   private
  128.     function GetFrameIndex(TimeStampMs: Cardinal): Integer;
  129.     procedure SetTotalTimeStamps(ATotalTimeStamps: Integer);
  130.   public
  131.     // Animation frame time stamps in milliseconds
  132.     TimeStampsMs: array of Cardinal;
  133.     // Frame transforms for each bone and each timestamp
  134.     Transforms: array of array of TAnimTransform;
  135.     // Current transform for each bone
  136.     AnimTransform: array of TAnimTransform;
  137.     // Total animation time in milliseconds
  138.     TotalMs: Cardinal;
  139.     function GetElementSize: Integer; override;
  140.     procedure AddProperties(const Result: Props.TProperties); override;
  141.     procedure SetProperties(Properties: Props.TProperties); override;
  142.     // Sets total bones
  143.     procedure SetTotalBones(ATotalBones: Integer);
  144.     // Adds to a bone with the given index an animation described by array of time stamps and corresponding bone transformations
  145.     procedure AddBoneAnim(ABoneIndex: Integer; ATimeStampsMs: array of Cardinal; AAnims: array of TAnimTransform);
  146.     // Scales the animation by the given amount
  147.     procedure DoScale(Amount: TVector3s);
  148.     // Rotates the animation by the given amount
  149.     procedure DoRotate(Amount: TVector3s);
  150.     // Sets animation time and recalculates current transforms
  151.     procedure SetTime(TimeStamp: TTimeUnit);
  152.   end;
  153.   // Animated skeleton class which encapsulates skeleton and animation resources
  154.   TAnimSkeleton = class
  155.   private
  156.     Animation: array of TAnimationResource;
  157.     TotalTransform: array of TMatrix4s;
  158.     Skeleton: TSkeletonResource;
  159.     FActiveAnimation: Integer;
  160.     function GetTotalBones: Integer;
  161.     function GetTotalAnimations: Integer;
  162.     function GetAnimationResource(Index: Integer): TAnimationResource;
  163.     procedure SetActiveAnimation(const Value: Integer);
  164.   public
  165. //    Head: PAnimSkeletonElement;
  166. //    OffsMatrices: array of TMatrix4s;
  167. //    Elements: array of PAnimSkeletonElement;
  168.     constructor Create;
  169.     destructor Destroy; override;
  170.     function GetElementByName(const Name: TShortName): PSkeletonElement;
  171.     procedure UpdateHierarchy;
  172.     procedure SetSkeletonRes(ASkeletonRes: TSkeletonResource);
  173.     procedure AddAnimation(AnimRes: TAnimationResource);
  174.     procedure RetrieveTransform(var Result: TAnimTransform; Index: Integer);
  175.     procedure DoScale(Amount: TVector3s);
  176.     // Rotates the skeleton by the given amount
  177.     procedure DoRotate(Amount: TVector3s);
  178.     // For active animation sets time and recalculates current transforms
  179.     procedure SetTime(Timestamp: TTimeUnit);
  180.     // Total number of bones in skeleton
  181.     property TotalBones: Integer read GetTotalBones;
  182.     // Skeleton hierarchy resource
  183.     property SkeletonResource: TSkeletonResource read Skeleton;
  184.     // Total number of animations
  185.     property TotalAnimations: Integer read GetTotalAnimations;
  186.     // Array of resources representing animations
  187.     property AnimationResource[Index: Integer]: TAnimationResource read GetAnimationResource;
  188.     // Currently active animation
  189.     property ActiveAnimation: Integer read FActiveAnimation write SetActiveAnimation;
  190.   end;
  191.   TSkinnedItem = class(TMesh)
  192.   private
  193.     FCurTime: TTimeUnit;
  194.     FTimeScale: Single;
  195.     FTotalAnimations: Integer;
  196.     procedure SetTime(const Value: TTimeUnit);
  197.     function GetTotalAnimations: Integer;
  198.   protected
  199.     procedure ResolveLinks; override;
  200.   public
  201.     Skeleton: TAnimSkeleton;
  202.     ShaderConsts: TShaderConstants;
  203.     constructor Create(AManager: TItemsManager); override;
  204.     procedure RetrieveShaderConstants(var ConstList: TShaderConstants); override;
  205.     procedure AddProperties(const Result: Props.TProperties); override;
  206.     procedure SetProperties(Properties: Props.TProperties); override;
  207.     procedure SetSkeleton(const ASkeleton: TAnimSkeleton);
  208.     function GetAnimRes: TArrayResource;
  209.     procedure Process(const DeltaT: Float); override;
  210.     property CurTime: TTimeUnit read FCurTime write SetTime;
  211.     property TimeScale: Single read FTimeScale write FTimeScale;
  212.     // Number of animations og the skinned item
  213.     property TotalAnimations: Integer read GetTotalAnimations;
  214.   end;
  215.   TSkeletalDummy = class(TProcessing)
  216.   private
  217.     BoneIndex: Integer;
  218.     function GetBaseItem(): TSkinnedItem;
  219.   protected
  220.     procedure ComputeTransform; override;
  221.   public
  222.     procedure AddProperties(const Result: Props.TProperties); override;
  223.     procedure SetProperties(Properties: Props.TProperties); override;
  224.     property BaseItem: TSkinnedItem read GetBaseItem;
  225.   end;
  226.   // Returns list of classes introduced by the unit
  227.   function GetUnitClassList: TClassArray;
  228. implementation
  229. function GetUnitClassList: TClassArray;
  230. begin
  231.   Result := GetClassList([TSkeletonResource, TAnimationResource, TAnimatedItem, TMorphedItem, TSkinnedItem, TSkeletalDummy]);
  232. end;
  233. function NewSkeletonElement: PSkeletonElement;
  234. begin
  235.   New(Result);
  236.   Result^.Index := -1;
  237.   Result^.Next := nil;
  238.   Result^.ChildHead := nil;
  239. end;
  240. { TAnimatedMesh }
  241. procedure TAnimatedTesselator.SetTotalFrames(const Value: Integer);
  242. begin
  243.   FTotalFrames := Value;
  244.   SetFrames(MinI(FTotalFrames-1, FFrame1), MinI(FTotalFrames-1, FFrame2), FFactor);
  245. end;
  246. destructor TAnimatedTesselator.Destroy;
  247. begin
  248.   if Assigned(Vertices) then FreeMem(Vertices);
  249.   if Assigned(Indices)  then FreeMem(Indices);
  250.   inherited;
  251. end;
  252. procedure TAnimatedTesselator.SetFrames(Frame1, Frame2: Integer; Factor: Single); 
  253. begin
  254.   if (Frame1 = FFrame1) and (Frame2 = FFrame2) and (Factor = FFactor) then Exit;
  255.   FFrame1 := Frame1;
  256.   FFrame2 := Frame2;
  257.   FFactor := Factor;
  258.   Update();
  259. end;
  260. procedure TAnimatedTesselator.Fill(AVerticesRes: TVerticesResource; AIndicesRes: TIndicesResource);
  261. var CurFrame: Integer;
  262. begin
  263.   Assert(Assigned(AVerticesRes), Format('%S.%S: VerticesRes is nil', [ClassName, 'Fill']));
  264.   VertexFormat     := AVerticesRes.Format;
  265.   NumberOfVertices := AVerticesRes.TotalElements;
  266.   TotalVertices    := NumberOfVertices;
  267.   ReallocMem(Vertices, AVerticesRes.DataSize);
  268.   Move(AVerticesRes.Data^, Vertices^, AVerticesRes.DataSize);
  269.   if Assigned(AIndicesRes) then begin
  270.     NumberOfIndices := AIndicesRes.TotalElements;
  271.     ReallocMem(Indices, AIndicesRes.DataSize);
  272.     Move(AIndicesRes.Data^, Indices^, AIndicesRes.DataSize);
  273.   end else begin
  274.     NumberOfIndices := 0;
  275.     ReallocMem(Indices, 0);
  276.   end;
  277.   Init();
  278.   CurFrame := FFrame1;
  279.   FFrame1 := -1;
  280.   SetFrames(CurFrame, CurFrame, 0);
  281. end;
  282. { TMorphedMesh }
  283. procedure TMorphedTesselator.SetTotalFrames(const Value: Integer);
  284. begin
  285.   inherited;
  286.   if Length(FrameVertices) < FTotalFrames then SetLength(FrameVertices, FTotalFrames);
  287.   if Length(FrameIndices)  < FTotalFrames then SetLength(FrameIndices,  FTotalFrames);
  288. end;
  289. procedure TMorphedTesselator.Update;
  290. var i: Integer; DestVec, SrcVec1, SrcVec2: ^TVector3s;
  291. begin
  292.   Assert((FFactor >= 0) and (FFactor <= 1));
  293.   if (TotalFrames = 0) or not Assigned(FrameVertices[0]) then Exit;
  294.   if FFactor < epsilon then begin
  295.     Move(FrameVertices[FFrame1]^, Vertices^, TotalVertices * FVertexSize);
  296.     Move(FrameIndices[FFrame1]^,  Indices^,  TotalIndices  * IndexSize);
  297.   end else if 1-FFactor < epsilon then begin
  298.     Move(FrameVertices[FFrame2]^, Vertices^, TotalVertices * FVertexSize);
  299.     Move(FrameIndices[FFrame2]^,  Indices^,  TotalIndices  * IndexSize);
  300.   end else begin
  301.     for i := 0 to TotalVertices-1 do begin
  302.       DestVec := @TByteBuffer(Vertices^)[i*FVertexSize];
  303.       SrcVec1 := @TByteBuffer(FrameVertices[FFrame1]^)[i*FVertexSize];
  304.       SrcVec2 := @TByteBuffer(FrameVertices[FFrame2]^)[i*FVertexSize];
  305.       DestVec^.X := SrcVec1^.X * (1-FFactor) + SrcVec2^.X * FFactor;
  306.       DestVec^.Y := SrcVec1^.Y * (1-FFactor) + SrcVec2^.Y * FFactor;
  307.       DestVec^.Z := SrcVec1^.Z * (1-FFactor) + SrcVec2^.Z * FFactor;
  308.     end;
  309.   end;
  310.   Invalidate([tbVertex], False);
  311. end;
  312. { TAnimatedItem }
  313. const GeomPrefix = 'GeometryFrame #%D ';       // Use in Format()
  314. procedure TAnimatedItem.SetTotalFrames(const Value: Integer);
  315. begin
  316.   FTotalFrames := Value;
  317.   if CurrentTesselator is TAnimatedTesselator then begin
  318.     TAnimatedTesselator(CurrentTesselator).TotalFrames := Value;
  319.     if FFrame >= TAnimatedTesselator(CurrentTesselator).TotalFrames then SetFrame(MaxI(0, TAnimatedTesselator(CurrentTesselator).TotalFrames-1));
  320.   end;
  321.   BuildItemLinks();
  322. end;
  323. procedure TAnimatedItem.SetFrame(const Value: Single);
  324. begin
  325.   FFrame := Value;
  326.   if MeshValid and (CurrentTesselator is TAnimatedTesselator) then begin
  327.     TAnimatedTesselator(CurrentTesselator).SetFrames(Trunc(Value), MinI(TotalFrames, Trunc(Value+1)), Frac(Value));
  328.   end;
  329. end;
  330. procedure TAnimatedItem.SetFrames(Frame1, Frame2: Integer; Factor: Single);
  331. begin
  332.   if MeshValid and (CurrentTesselator is TAnimatedTesselator) then
  333.     TAnimatedTesselator(CurrentTesselator).SetFrames(Frame1, Frame2, Factor);
  334.   FFrame := Frame1;
  335. end;
  336. procedure TAnimatedItem.OnSceneLoaded;
  337. begin
  338.   inherited;
  339.   SetMesh();
  340. end;
  341. procedure TAnimatedItem.AddProperties(const Result: Props.TProperties);
  342. begin
  343.   inherited;
  344.   if Assigned(Result) then begin
  345.     Result.Add('Total frames', vtInt, [], IntToStr(FTotalFrames),  '');
  346.     Result.Add('Frame', vtSingle, [], FloatToStr(FFrame), Format('%D-%D', [0, FTotalFrames-1]));
  347.   end;
  348. end;
  349. procedure TAnimatedItem.SetProperties(Properties: Props.TProperties);
  350. begin
  351.   inherited;
  352.   if Properties.Valid('Total frames') then TotalFrames := StrToIntDef(Properties['Total frames'], FTotalFrames);
  353.   if Properties.Valid('Frame') then SetFrame(StrToFloatDef(Properties['Frame'], FFrame));
  354. end;
  355. { TMorphedItem }
  356. function TMorphedItem.GetFrameIndicesRes(Index: Integer): TIndicesResource;
  357. var Item: TItem;
  358. begin
  359.   if ResolveLink(Format(GeomPrefix + 'indices', [Index]), Item) or (Item is TIndicesResource) then
  360.     Result := Item as TIndicesResource else
  361.       Result := nil;
  362. end;
  363. function TMorphedItem.GetFrameVerticesRes(Index: Integer): TVerticesResource;
  364. var Item: TItem;
  365. begin
  366.   if ResolveLink(Format(GeomPrefix + 'vertices', [Index]), Item) or (Item is TVerticesResource) then
  367.     Result := Item as TVerticesResource else
  368.       Result := nil;
  369. end;
  370. procedure TMorphedItem.SetMesh;
  371. var i: Integer; Mesh: TMorphedTesselator;
  372. begin
  373.   inherited;
  374.   MeshValid := False;
  375.   if CurrentTesselator is TMorphedTesselator then Mesh := TMorphedTesselator(CurrentTesselator) else Exit;
  376.   if not Assigned(FrameVertices[0]) then Exit;
  377.   Mesh.TotalFrames      := TotalFrames;
  378.   Mesh.Fill(FrameVertices[0], FrameIndices[0]);
  379.   MeshValid := True;
  380.   for i := 0 to TotalFrames-1 do if Assigned(FrameVertices[i]) then begin
  381.     Mesh.FrameVertices[i] := FrameVertices[i].Data;
  382. //    Mesh.NumberOfVertices := FrameVertices[i].TotalElements;
  383.     if (Mesh.NumberOfIndices > 0) and Assigned(FrameIndices[i]) then begin
  384.       Mesh.FrameIndices[i] := FrameIndices[i].Data;
  385.       
  386.       if FrameIndices[i].TotalElements <> Mesh.NumberOfIndices then begin
  387.         MeshValid := False;
  388.         {$IFDEF LOGGING}
  389.         Log.Log(Format('%S("%S").%S: Number of indices doesn''t match for all frames', [ClassName, Name, 'SetMesh']), lkError);
  390.         {$ENDIF}
  391.       end;
  392.     end;
  393.     if (FrameVertices[i].Format <> Mesh.VertexFormat) or (FrameVertices[i].TotalElements <> Mesh.NumberOfVertices) then begin
  394.       MeshValid := False;
  395.       {$IFDEF LOGGING}
  396.       Log.Log(Format('%S("%S").%S: Format or number of vertices doesn''t match for all frames', [ClassName, Name, 'SetMesh']), lkError);
  397.       {$ENDIF}
  398.     end;
  399.   end;
  400.   if CurrentTesselator <> nil then begin
  401.     CurrentTesselator.Init();
  402.     BoundingBox := CurrentTesselator.GetBoundingBox;
  403.   end;
  404.   
  405.   SetFrame(FFrame);
  406. end;
  407. function TMorphedItem.GetTesselatorClass: CTesselator; begin Result := TMorphedTesselator; end;
  408. procedure TMorphedItem.AddProperties(const Result: Props.TProperties);
  409. var i: Integer;
  410. begin
  411.   inherited;
  412.   for i := 0 to FTotalFrames-1 do begin
  413.     AddItemLink(Result, Format(GeomPrefix + 'vertices', [i]), [], 'TVerticesResource');
  414.     AddItemLink(Result, Format(GeomPrefix + 'indices',  [i]), [], 'TIndicesResource');
  415.   end;
  416. end;
  417. procedure TMorphedItem.SetProperties(Properties: Props.TProperties);
  418. var i: Integer;
  419. begin
  420.   inherited;
  421.   for i := 0 to FTotalFrames-1 do begin
  422.     if Properties.Valid(Format(GeomPrefix + 'vertices', [i])) then
  423.       SetLinkProperty(Format(GeomPrefix + 'vertices', [i]), Properties[Format(GeomPrefix + 'vertices', [i])]);
  424.     if Properties.Valid(Format(GeomPrefix + 'indices', [i])) then
  425.       SetLinkProperty(Format(GeomPrefix + 'indices', [i]), Properties[Format(GeomPrefix + 'indices', [i])]);
  426.   end;
  427.   SetMesh();
  428. end;
  429. { TSkinnedItem }
  430. procedure TSkinnedItem.SetTime(const Value: TTimeUnit);
  431. var i: Integer;
  432. begin
  433.   FCurTime := Value;
  434. //  CurrentTesselator.Invalidate([tbVertex], False);
  435.   if Assigned(Skeleton) and Assigned(Skeleton.SkeletonResource) then begin
  436.     Skeleton.SetTime(FCurTime);
  437.     if Length(BlendMatrices) <> Skeleton.Skeleton.TotalBones then SetLength(BlendMatrices, Skeleton.Skeleton.TotalBones);
  438.     for i := 0 to High(BlendMatrices) do begin
  439. //      Skeleton.Elements[i]^.TotalTransform := MulMatrix4s(Skeleton.OffsMatrices[i], Skeleton.Elements[i]^.TotalTransform);
  440. //      BlendMatrices[i] := Skeleton.Elements[i]^.TotalTransform;
  441.       Skeleton.RetrieveTransform(BlendMatrices[i], i);
  442.       BlendMatrices[i] := MulMatrix4s(BlendMatrices[i], Transform);
  443.     end;
  444.     InvalidateTransform();
  445.   end;
  446. end;
  447. function TSkinnedItem.GetTotalAnimations: Integer;
  448. begin
  449.   Result := 0;
  450.   if Assigned(Skeleton) then Result := Skeleton.TotalAnimations;
  451.   if FTotalAnimations <> -1 then Result := FTotalAnimations;  
  452. end;
  453. procedure TSkinnedItem.ResolveLinks;
  454. var i: Integer; Item: TItem;
  455. begin
  456.   inherited;
  457.   if not Assigned(Skeleton) then Exit;
  458.   if ResolveLink('GeometrySkeleton', Item) then Skeleton.SetSkeletonRes(Item as TSkeletonResource);
  459.   for i := 0 to TotalAnimations-1 do
  460.     if ResolveLink('GeometryAnimation #' + IntToStr(i), Item) then Skeleton.AddAnimation(Item as TAnimationResource);
  461.   FTotalAnimations := -1;           // Let TotalAnimations be determined by skeleton
  462. end;
  463. constructor TSkinnedItem.Create(AManager: TItemsManager);
  464. begin
  465.   Skeleton := TAnimSkeleton.Create;
  466.   FTotalAnimations := -1;
  467.   inherited;
  468. end;
  469. procedure TSkinnedItem.RetrieveShaderConstants(var ConstList: TShaderConstants);
  470. //var i: Integer;
  471. begin
  472.   inherited;
  473. {  SetLength(ConstList, GetAnimRes.DataSize div SizeOf(TMatrix4s)*4);
  474.   for i := 0 to High(ConstList) do begin
  475.     ConstList[i].ShaderKind := skVertex;
  476.     ConstList[i].ShaderRegister :=
  477.   end;
  478.   ConstList := ShaderConsts;}
  479. end;
  480. procedure TSkinnedItem.AddProperties(const Result: TProperties);
  481. var i: Integer;
  482. begin
  483.   inherited;
  484.   AddItemLink(Result, 'GeometrySkeleton', [], 'TSkeletonResource');
  485.   if Assigned(Skeleton) then for i := 0 to TotalAnimations-1 do
  486.     AddItemLink(Result, 'GeometryAnimation #' + IntToStr(i), [], 'TAnimationResource');
  487.   if Assigned(Result) then begin
  488.     Result.Add('GeometryTotal animations', vtInt, [poReadonly], IntToStr(TotalAnimations), '');
  489.     Result.Add('Time', vtSingle, [], FloatToStr(FCurTime), Format('%D-%D', [0, 10]));
  490.     Result.Add('Time scale', vtSingle, [], FloatToStr(FTimeScale), Format('%D-%D', [0, 10]));
  491.   end;
  492. end;
  493. procedure TSkinnedItem.SetProperties(Properties: TProperties);
  494. var i: Integer;
  495. begin
  496.   inherited;
  497.   if Properties.Valid('GeometryTotal animations') then
  498.     FTotalAnimations := StrToIntDef(Properties['GeometryTotal animations'], 0);          // Only used for loading
  499.   BuildItemLinks;  
  500.   if Properties.Valid('GeometrySkeleton') then SetLinkProperty('GeometrySkeleton', Properties['GeometrySkeleton']);
  501.   if Assigned(Skeleton) then for i := 0 to TotalAnimations-1 do
  502.     if Properties.Valid('GeometryAnimation #' + IntToStr(i)) then
  503.       SetLinkProperty('GeometryAnimation #' + IntToStr(i), Properties['GeometryAnimation #' + IntToStr(i)]);
  504.   if Properties.Valid('Time') then CurTime := StrToFloatDef(Properties['Time'], 0);
  505.   if Properties.Valid('Time scale') then TimeScale := StrToFloatDef(Properties['Time scale'], 0);
  506.   SetMesh();
  507. end;
  508. procedure TSkinnedItem.SetSkeleton(const ASkeleton: TAnimSkeleton);
  509. begin
  510.   Skeleton := ASkeleton;
  511. end;
  512. function TSkinnedItem.GetAnimRes: TArrayResource;
  513. var Item: TItem;
  514. begin
  515.   if ResolveLink('GeometryAnimation', Item) then
  516.     Result := Item as TArrayResource
  517.   else if Item is TArrayResource then
  518.     Result := Item as TArrayResource
  519.   else
  520.     Result := nil;
  521. end;
  522. procedure TSkinnedItem.Process(const DeltaT: Float);
  523. begin
  524.   inherited;
  525.   CurTime := CurTime + DeltaT * FTimeScale;
  526. end;
  527. { TAnimSkeleton }
  528. function TAnimSkeleton.GetTotalBones: Integer;
  529. begin
  530.   if Assigned(Skeleton) then Result := Skeleton.TotalBones else Result := 0;
  531. end;
  532. function TAnimSkeleton.GetTotalAnimations: Integer;
  533. begin
  534.   Result := Length(Animation);
  535. end;
  536. function TAnimSkeleton.GetAnimationResource(Index: Integer): TAnimationResource;
  537. begin
  538.   Result := Animation[Index];
  539. end;
  540. procedure TAnimSkeleton.SetActiveAnimation(const Value: Integer);
  541. begin
  542.   FActiveAnimation := Value;
  543.   if FActiveAnimation > High(Animation) then FActiveAnimation := -1;
  544. end;
  545. constructor TAnimSkeleton.Create;
  546. begin
  547. {  Head.Name := '';
  548.   Head.Transform := IdentityMatrix4s;
  549.   Head.Next := nil;
  550.   Head.ChildHead := nil;}
  551.   FActiveAnimation := -1;
  552. end;
  553. destructor TAnimSkeleton.Destroy;
  554. begin
  555.   inherited;
  556. end;
  557. function TAnimSkeleton.GetElementByName(const Name: TShortName): PSkeletonElement;
  558.   function FindInElement(Element: PSkeletonElement): PSkeletonElement;
  559.   begin
  560.     Result:= Element;
  561.     if Name = Skeleton.ElementNames[Element^.Index] then Exit;
  562.     if Assigned(Element^.ChildHead) then begin
  563.       Result := FindInElement(Element^.ChildHead);
  564.       if Assigned(Result) then Exit;
  565.     end;
  566.     if Assigned(Element^.Next) then begin
  567.       Result := FindInElement(Element^.Next);
  568.       if Assigned(Result) then Exit;
  569.     end;
  570.     Result:= nil;
  571.   end;
  572. begin
  573.   if Assigned(Skeleton.Head) then Result := FindInElement(Skeleton.Head) else Result := nil;
  574. end;
  575. procedure TAnimSkeleton.UpdateHierarchy;
  576.   procedure UpdateElements(Element: PSkeletonElement; const MatCur: TMatrix4s);
  577.   var Child: PSkeletonElement; Ind: Integer;
  578.   begin
  579.     Ind := Element^.Index;
  580.     Assert(Ind <> -1);
  581. //    if ind = -1 then Exit;
  582.     TotalTransform[Ind] := MulMatrix4s(Animation[FActiveAnimation].AnimTransform[Ind], MatCur);
  583.     Child := Element^.ChildHead;
  584.     while Assigned(Child) do begin
  585.       UpdateElements(Child, TotalTransform[Ind]);
  586.       Child := Child^.Next;
  587.     end;
  588.   end;
  589. begin
  590.   UpdateElements(Skeleton.Head, IdentityMatrix4s);
  591. end;
  592. procedure TAnimSkeleton.SetSkeletonRes(ASkeletonRes: TSkeletonResource);
  593. begin
  594.   Skeleton := ASkeletonRes;
  595.   if Assigned(Skeleton) then SetLength(TotalTransform, Skeleton.TotalBones);
  596. end;
  597. procedure TAnimSkeleton.AddAnimation(AnimRes: TAnimationResource);
  598. begin
  599.   Assert(Assigned(AnimRes));
  600.   if not Assigned(AnimRes) then Exit;
  601.   SetLength(Animation, Length(Animation)+1);
  602.   Animation[High(Animation)] := AnimRes;
  603.   if FActiveAnimation = -1 then FActiveAnimation := 0;
  604. end;
  605. procedure TAnimSkeleton.RetrieveTransform(var Result: TAnimTransform; Index: Integer);
  606. begin
  607.   MulMatrix4s(Result, Skeleton.OffsTransform[Index], TotalTransform[Index]);
  608. end;
  609. procedure TAnimSkeleton.DoScale(Amount: TVector3s);
  610. var i: Integer;
  611. begin
  612.   Skeleton.DoScale(Amount);
  613.   for i := 0 to High(Animation) do Animation[i].DoScale(Amount);
  614. end;
  615. procedure TAnimSkeleton.DoRotate(Amount: TVector3s);
  616. var i: Integer;
  617. begin
  618.   Skeleton.DoRotate(Amount);
  619.   for i := 0 to High(Animation) do Animation[i].DoRotate(Amount);
  620. end;
  621. procedure TAnimSkeleton.SetTime(Timestamp: TTimeUnit);
  622. begin
  623.   if FActiveAnimation = -1 then Exit;
  624.   Animation[FActiveAnimation].SetTime(Timestamp);
  625.   UpdateHierarchy();
  626. end;
  627. { TSkeletonResource }
  628. procedure TSkeletonResource.FreeSkeleton(El: PSkeletonElement);
  629. var TempEl, CurEl: PSkeletonElement;
  630. begin
  631.   if not Assigned(El) then Exit;
  632.   CurEl := El;
  633.   while Assigned(CurEl) do begin
  634.     FreeSkeleton(CurEl^.ChildHead);
  635.     TempEl := CurEl^.Next;
  636.     Dispose(CurEl);
  637.     CurEl := TempEl;
  638.   end;
  639. end;
  640. procedure TSkeletonResource.AddElementProperties(Element: PSkeletonElement; const Result: TProperties; const Prefix: AnsiString);
  641. var i: Integer; Pref: AnsiString;
  642. begin
  643.   if not Assigned(Element) then Exit;
  644.   Result.Add(Prefix + HierarchyDelimiter + 'Name', vtString, [], ElementNames[Element^.Index], '');
  645.   Pref := Prefix + ElementNames[Element^.Index] + HierarchyDelimiter;
  646.   for i := 0 to 3 do AddVector4sProperty(Result, Pref + 'Offs transform row#' + IntToStr(i), OffsTransform[Element^.Index].Rows[i]);
  647. end;
  648. procedure TSkeletonResource.SetElementProperties(Element: PSkeletonElement; Properties: TProperties; const Prefix: AnsiString);
  649. begin
  650.   if not Assigned(Element) then Exit;
  651. //  Inc(FTotalBones);
  652. end;
  653. destructor TSkeletonResource.Destroy;
  654. begin
  655.   FreeSkeleton(Head);
  656.   inherited;
  657. end;
  658. function TSkeletonResource.GetElementSize: Integer;
  659. begin
  660.   Result := SizeOf(TSkeletonElement);
  661. end;
  662. procedure TSkeletonResource.AddProperties(const Result: TProperties);
  663.   procedure BuildTree();
  664.   var TotalIndices, TotalCounts: Integer;
  665.     procedure AddCount(ACount: Integer);
  666.     begin
  667.       if Length(HCounts) <= TotalCounts then SetLength(HCounts, Totalcounts+1);
  668.       HCounts[TotalCounts] := ACount;
  669.       Inc(TotalCounts);
  670.     end;
  671.     procedure AddIndex(AIndex: Integer);
  672.     begin
  673.       if Length(HIndices) <= TotalIndices then SetLength(HIndices, TotalIndices+1);
  674.       HIndices[TotalIndices] := AIndex;
  675.       Inc(TotalIndices);
  676. //      Log.Log(' ****** Saved bone #' + IntToStr(High(Indices)) + ' "' + ElementNames[AIndex] + '", ind: ' + IntToStr(AIndex));
  677.     end;
  678.     procedure CountChilds(SkEl: PSkeletonElement);
  679.     var CurEl: PSkeletonElement; Count: Integer;
  680.     begin
  681. //      Log.Log(' ****** Level up #' + IntToStr(High(Counts)));
  682.       CurEl := SkEl^.ChildHead;                   //
  683.       Count := 0;                                 //            7
  684.       while Assigned(CurEl) do begin              //           /
  685.         AddIndex(CurEl^.Index);                   //      5-4-6
  686.         Inc(Count);                               //       
  687.         CurEl := CurEl^.Next;                     //    2---3
  688.       end;                                        //     
  689.       AddCount(Count);                            //      1
  690.                                                   //     /         0  1  2 3  5 4 6  7
  691.       CurEl := SkEl^.ChildHead;                   //    0       1  1  2  0 3  0 0 1  0
  692.       while Assigned(CurEl) do begin
  693.         CountChilds(CurEl);
  694.         CurEl := CurEl^.Next;
  695.       end;
  696.     end;
  697.   begin
  698.     TotalIndices := 0;
  699.     TotalCounts  := 0;
  700.     AddIndex(Head^.Index);
  701.     CountChilds(Head);
  702. //    Log.Log(' ****** Saved hierarchy: C: ' + IntToStr(Length(Counts)) + ', I: ' + IntToStr(Length(Indices)));
  703.   end;
  704. var i: Integer;
  705. begin
  706.   inherited;
  707.   if not Assigned(Result) then Exit;
  708.   Result.Add('Total bones', vtInt, [poReadonly], IntToStr(FTotalBones), '');
  709.   Result.AddBinary('Offset transforms', [poReadonly, poHidden], @OffsTransform[0], FTotalBones * SizeOf(TAnimTransform));
  710.   for i := 0 to FTotalBones-1 do
  711.     Result.Add('HierarchyBone name #' + IntToStr(i), vtString, [], ElementNames[i], '', '');
  712.   // Build and serialize bone tree
  713.   BuildTree();
  714.   Result.AddBinary('HierarchyCounts',  [poReadonly, poHidden], @HCounts[0],  Length(HCounts)  * SizeOf(Integer));
  715.   Result.AddBinary('HierarchyIndices', [poReadonly, poHidden], @HIndices[0], Length(HIndices) * SizeOf(Integer));
  716. //  Log.Log(' ****** C: ' + IntToStr(Counts[High(Counts)]) + ', I: ' + IntToStr(Indices[High(Indices)]));
  717. end;
  718. procedure TSkeletonResource.SetProperties(Properties: TProperties);
  719. var StartIndex, StartCount: Integer;
  720.   procedure SetChilds(ParentEl: PSkeletonElement);
  721.   var i: Integer; NewEl, CurEl: PSkeletonElement;
  722.   begin                                                             //
  723.     Log.Log(' ****** Level up #' + IntToStr(StartCount));
  724.     CurEl := nil;                                                   //
  725.     for i := 0 to HCounts[StartCount]-1 do begin                     //
  726.       NewEl := NewSkeletonElement();                                //
  727.       if i = 0 then                                                 //   4   5  6
  728.         ParentEl^.ChildHead := NewEl                                //     /  /
  729.       else                                                          //  0--2--3
  730.         CurEl^.Next := NewEl;                                       //           c  3 0 2 1 0 0 0
  731.       CurEl := NewEl;                                               //    1       i  1 0 2 3 4 5 6
  732. //      Log.Log(' ****** Loading bone #' + IntToStr(StartIndex));
  733. //      Log.Log(' ****** Loading bone #' + IntToStr(StartIndex) + ' "' + ElementNames[HIndices[StartIndex]] + '", ind: ' + IntToStr(HIndices[StartIndex]));
  734.       CurEl^.Index := HIndices[StartIndex];
  735.       Inc(StartIndex);
  736.     end;
  737.     CurEl := ParentEl^.ChildHead;
  738.     for i := 0 to HCounts[StartCount]-1 do begin
  739.       Inc(StartCount);      
  740.       SetChilds(CurEl);
  741.       CurEl := CurEl^.Next;
  742.     end;
  743.   end;
  744. var
  745.   i: Integer;
  746. begin
  747.   inherited;
  748.   if Properties.Valid('Total bones') then TotalBones := StrToIntDef(Properties['Total bones'], 0);
  749.   Log.Log(' ****** Loading hierarchy');
  750.   if Properties.Valid('Offset transforms') then begin
  751.     if TotalBones > 0 then Properties.RetrieveBinPropertyData('Offset transforms', @OffsTransform[0]);
  752.   end else
  753.     Log.Log(ClassName + '.SetProperties: offset transforms data not found', lkError);
  754.   for i := 0 to FTotalBones-1 do
  755.     if Properties.Valid('HierarchyBone name #' + IntToStr(i)) then
  756.       ElementNames[i] := Properties['HierarchyBone name #' + IntToStr(i)];
  757.   SetLength(HCounts, Properties.GetBinPropertySize('HierarchyCounts', SizeOf(Integer)));
  758.   if Assigned(HCounts) then Properties.RetrieveBinPropertyData('HierarchyCounts', @HCounts[0]);
  759.   SetLength(HIndices, Properties.GetBinPropertySize('HierarchyIndices', SizeOf(Integer)));
  760.   if Assigned(HIndices) then Properties.RetrieveBinPropertyData('HierarchyIndices', @HIndices[0]);
  761. //  Log.Log(' ****** C: ' + IntToStr(Counts[High(Counts)]) + ', I: ' + IntToStr(Indices[High(Indices)]));
  762.   FreeSkeleton(Head);
  763.   if Length(HCounts) > 0 then begin
  764. //    Log.Log(' ****** Loading hierarchy: C: ' + IntToStr(Length(Counts)) + ', I: ' + IntToStr(Length(Indices)));
  765.     Head := NewSkeletonElement();
  766.     Head^.Index := HIndices[0];
  767.     StartIndex := 1;
  768.     StartCount := 0;
  769.     SetChilds(Head);
  770.   end;
  771. end;
  772. procedure TSkeletonResource.SetTotalBones(ATotalBones: Integer);
  773. begin
  774.   FTotalBones := ATotalBones;
  775. //  if Length(OffsTransform) >= TotalBones then Exit;
  776.   SetLength(OffsTransform, FTotalBones);
  777.   SetLength(ElementNames,  FTotalBones);
  778. end;
  779. procedure TSkeletonResource.DoScale(Amount: TVector3s);
  780. var i: Integer;
  781. begin
  782.   for i := 0 to High(OffsTransform) do begin
  783.     OffsTransform[i]._41 := OffsTransform[i]._41 * Amount.X;
  784.     OffsTransform[i]._42 := OffsTransform[i]._42 * Amount.Y;
  785.     OffsTransform[i]._43 := OffsTransform[i]._43 * Amount.Z;
  786.   end;
  787. end;
  788. procedure TSkeletonResource.DoRotate(Amount: TVector3s);
  789. var i: Integer; RotMatrix: TMatrix3s;
  790. begin
  791.   RotMatrix := MulMatrix3s(ZRotationMatrix3s(Amount.Z/180*pi), YRotationMatrix3s(Amount.Y/180*pi));
  792.   RotMatrix := MulMatrix3s(XRotationMatrix3s(Amount.X/180*pi), RotMatrix);
  793.   for i := 0 to High(OffsTransform) do
  794. //    OffsTransform[i].ViewTranslate := Transform3Vector3s(RotMatrix, OffsTransform[i].ViewTranslate);
  795.     OffsTransform[i] := MulMatrix4s(OffsTransform[i], ExpandMatrix3s(RotMatrix));
  796. end;
  797. function TSkeletonResource.NewSkeletonElement: PSkeletonElement;
  798. begin
  799.   New(Result);
  800.   Result^.Index := FTotalBones;
  801.   Result^.Next := nil;
  802.   Result^.ChildHead := nil;
  803. end;
  804. { TAnimationResource }
  805. function TAnimationResource.GetFrameIndex(TimeStampMs: Cardinal): Integer;
  806. begin
  807. end;
  808. procedure TAnimationResource.SetTotalTimeStamps(ATotalTimeStamps: Integer);
  809. var i: Integer;
  810. begin
  811.   SetLength(TimeStampsMS, ATotalTimeStamps);
  812.   for i := 0 to High(Transforms) do SetLength(Transforms[i], ATotalTimeStamps);
  813. end;
  814. function TAnimationResource.GetElementSize: Integer;
  815. begin
  816.   Result := SizeOf(TAnimTransform);
  817. end;
  818. procedure TAnimationResource.AddProperties(const Result: Props.TProperties);
  819. var i: Integer;
  820. begin
  821.   inherited;
  822.   if not Assigned(Result) then Exit;
  823.   Result.Add('Total time, ms', vtInt, [],           IntToStr(TotalMs), '');
  824.   Result.Add('Total frames',   vtInt, [poReadonly], IntToStr(Length(TimeStampsMs)), '');
  825.   Result.Add('DataTotal bones', vtInt, [poReadonly], IntToStr(Length(Transforms)), '');
  826.   Result.AddBinary('DataTimestamps', [poReadonly, poHidden], @TimeStampsMs[0], Length(TimeStampsMs) * SizeOf(Cardinal));
  827.   for i := 0 to High(Transforms) do
  828.     Result.AddBinary('DataBone #' + IntToStr(i), [poReadonly, poHidden], @Transforms[i][0], Length(Transforms[i]) * SizeOf(TAnimTransform));
  829. end;
  830. procedure TAnimationResource.SetProperties(Properties: Props.TProperties);
  831. var i: Integer;
  832. begin
  833.   inherited;
  834.   if Properties.Valid('Total time, ms') then TotalMs := StrToIntDef(Properties['Total time, ms'], 0);
  835.   if Properties.Valid('DataTotal bones') then SetTotalBones(StrToIntDef(Properties['DataTotal bones'], 0));
  836.   if Properties.Valid('Total frames') then SetTotalTimeStamps(StrToIntDef(Properties['Total frames'], 0));
  837.   Properties.RetrieveBinPropertyData('DataTimestamps', @TimeStampsMs[0]);      // ToFix: avoid range error
  838.   for i := 0 to High(Transforms) do
  839.     Properties.RetrieveBinPropertyData('DataBone #' + IntToStr(i), @Transforms[i][0]);      // ToFix: avoid range error
  840. end;
  841. procedure TAnimationResource.SetTotalBones(ATotalBones: Integer);
  842. begin
  843.   SetLength(Transforms,    ATotalBones);
  844.   SetLength(AnimTransform, ATotalBones);
  845. end;
  846. procedure TAnimationResource.AddBoneAnim(ABoneIndex: Integer; ATimeStampsMs: array of Cardinal; AAnims: array of TAnimTransform);
  847.   procedure InsertAt(Index: Integer);
  848.   var Bone, i: Integer;
  849.   begin
  850.     SetTotalTimeStamps(Length(TimeStampsMS)+1);
  851.     for i := High(TimeStampsMs) downto Index+1 do begin
  852.       TimeStampsMs[i] := TimeStampsMs[i+1];
  853.       for Bone := 0 to High(Transforms) do
  854.         Transforms[Bone, i] := Transforms[Bone, i-1];
  855.     end;
  856.   end;
  857.   function GetTimeIndex(TimeMs: Cardinal): Integer;
  858.   begin
  859.     Result := 0;
  860.     while (Result <= High(TimeStampsMs)) and (TimeMs > TimeStampsMs[Result]) do Inc(Result);
  861.     if (Result > High(TimeStampsMs)) or (TimeMs > TimeStampsMs[Result]) then InsertAt(Result);
  862.   end;
  863. var
  864.   i, Ind: Integer;
  865. begin
  866.   Assert(Length(ATimeStampsMs) = Length(AAnims));
  867.   for i := 0 to High(ATimeStampsMs) do begin
  868.     Ind := GetTimeIndex(ATimeStampsMs[i]);
  869.     TimeStampsMs[Ind] := ATimeStampsMs[i];
  870.     Transforms[ABoneIndex, Ind] := AAnims[i];
  871.     if TotalMs < TimeStampsMs[Ind] then TotalMs := TimeStampsMs[Ind];
  872. {
  873.     if not Assigned(Skeleton.Animation[0].Transforms[SkelEl^.Index]) then
  874.       SetLength(Skeleton.Animation[0].Transforms[SkelEl^.Index], Frame.m_cMatrixKeys);
  875.     for i := 0 to High(Skeleton.Animation[0].TimeStampsMs) do begin
  876.       Skeleton.Animation[0].TimeStampsMs[i] := Frame.m_pMatrixKeys[i].dwTime;
  877.       Skeleton.Animation[0].Transforms[SkelEl^.Index, i] := TMatrix4s(Frame.m_pMatrixKeys[i].mat);
  878.       if Skeleton.Animation[0].TotalMs < Skeleton.Animation[0].TimeStampsMs[i] then
  879.         Skeleton.Animation[0].TotalMs := Skeleton.Animation[0].TimeStampsMs[i]}
  880.   end;
  881. end;
  882. procedure TAnimationResource.DoScale(Amount: TVector3s);
  883. var i, j: Integer;
  884. begin
  885.   for i := 0 to High(Transforms) do begin
  886.     // Scale translation part of current transforms
  887.     AnimTransform[i]._41 := AnimTransform[i]._41 * Amount.X;
  888.     AnimTransform[i]._42 := AnimTransform[i]._42 * Amount.Y;
  889.     AnimTransform[i]._43 := AnimTransform[i]._43 * Amount.Z;
  890.     for j := 0 to High(Transforms[i]) do begin                // Scale translation part of animation transforms
  891.       Transforms[i, j]._41 := Transforms[i, j]._41 * Amount.X;
  892.       Transforms[i, j]._42 := Transforms[i, j]._42 * Amount.Y;
  893.       Transforms[i, j]._43 := Transforms[i, j]._43 * Amount.Z;
  894.     end;
  895.   end;
  896. end;
  897. procedure TAnimationResource.DoRotate(Amount: TVector3s);
  898. var i, j: Integer; RotMatrix: TMatrix3s;
  899. begin
  900.   RotMatrix := MulMatrix3s(ZRotationMatrix3s(Amount.Z/180*pi), YRotationMatrix3s(Amount.Y/180*pi));
  901.   RotMatrix := MulMatrix3s(XRotationMatrix3s(-Amount.X/180*pi), RotMatrix);
  902.   for i := 0 to High(Transforms) do begin
  903.     // Rotate translation part of current transforms
  904. //    AnimTransform[i].ViewTranslate := Transform3Vector3s(RotMatrix, AnimTransform[i].ViewTranslate);
  905.     AnimTransform[i] := MulMatrix4s(AnimTransform[i], ExpandMatrix3s(RotMatrix));
  906.     for j := 0 to High(Transforms[i]) do                 // Rotate translation part of animation transforms
  907.       Transforms[i, j] := MulMatrix4s(Transforms[i, j], ExpandMatrix3s(RotMatrix));
  908. //      Transforms[i, j].ViewTranslate := Transform3Vector3s(RotMatrix, Transforms[i, j].ViewTranslate);
  909.   end;
  910. end;
  911. procedure TAnimationResource.SetTime(TimeStamp: TTimeUnit);
  912. var
  913.   i, Ind, i1, i2: Integer;
  914.   LerpValue: Single;
  915.   TimeStampMs: Cardinal;
  916. begin
  917.   TimeStampMs := TimeUnitToMs(TimeStamp) mod TotalMs;
  918.   i1 := 0;
  919.   i2 := 0;
  920.     // ToFix: rewrite
  921.     for Ind := 0 to High(TimeStampsMs) do if (TimeStampsMs[Ind] > TimeStampMs) then begin
  922.       i2 := Ind;
  923.       if (Ind > 0) then i1 := Ind - 1 else i1 := Ind;
  924.       Break;
  925.     end;
  926.   if ((TimeStampsMs[i2] - TimeStampsMs[i1]) = 0) then
  927.     LerpValue := 0
  928.   else
  929.     LerpValue := (TimeStampMs - TimeStampsMs[i1]) / (TimeStampsMs[i2] - TimeStampsMs[i1]);
  930.   if (LerpValue > 0.5) then Ind := i2 else Ind := i1;
  931.   for i := 0 to High(AnimTransform) do if Assigned(Transforms[i]) then
  932.     AnimTransform[i] := Transforms[i, Ind];
  933. end;
  934. { TSkeletalDummy }
  935. procedure TSkeletalDummy.ComputeTransform;
  936. begin
  937.   if Assigned(BaseItem) then begin
  938.     BaseItem.Skeleton.RetrieveTransform(FTransform, BoneIndex);
  939.     FTransform := MulMatrix4s(FTransform, BaseItem.Transform);
  940.   end;
  941.   TransformValid := True;
  942. end;
  943. function TSkeletalDummy.GetBaseItem: TSkinnedItem;
  944. var Item: TItem;
  945. begin
  946.   ResolveLink('Base item', Item);
  947.   Result := TSkinnedItem(Item);
  948. end;
  949. procedure TSkeletalDummy.AddProperties(const Result: Props.TProperties);
  950. var BonesEnum: AnsiString;
  951. begin
  952.   inherited;
  953.   AddItemLink(Result, 'Base item', [], 'TSkinnedItem');
  954.   if not Assigned(Result) then Exit;
  955.   BonesEnum := '';
  956.   if Assigned(BaseItem) then
  957.     BonesEnum := StringsToEnumA(BaseItem.Skeleton.Skeleton.ElementNames, True);
  958.   Result.AddEnumerated('Bone index', [], BoneIndex, BonesEnum);
  959. end;
  960. procedure TSkeletalDummy.SetProperties(Properties: Props.TProperties);
  961. begin
  962.   inherited;
  963.   if Properties.Valid('Base item') then SetLinkProperty('Base item', Properties['Base item']);
  964.   if Properties.Valid('Bone index') then BoneIndex := Properties.GetAsInteger('Bone index');
  965. end;
  966. begin
  967.   GlobalClassList.Add('C2Anim', GetUnitClassList);
  968. end.