//Animations private EAN_Animation ParseAnimation(int offset, int nameOffset, int animIndex) { List <ESK_BoneNonHierarchal> bonesNonHierachal = eanFile.Skeleton.GetNonHierarchalBoneList(); EAN_Animation animation = new EAN_Animation(); byte indexSize = rawBytes[offset + 2]; byte floatSize = rawBytes[offset + 3]; int nodeCount = BitConverter.ToInt32(rawBytes, offset + 8); int nodeOffset = BitConverter.ToInt32(rawBytes, offset + 12) + offset; //animation header data ValidateFloatAndIntPrecision(indexSize, floatSize); animation.I_02 = (EAN_Animation.IntPrecision)indexSize; animation.I_03 = (EAN_Animation.FloatPrecision)floatSize; animation.I_04 = BitConverter.ToInt32(rawBytes, offset + 4); if (nodeCount > 0) { animation.Nodes = new ObservableCollection <EAN_Node>(); for (int i = 0; i < nodeCount; i++) { int thisNodeOffset = BitConverter.ToInt32(rawBytes, nodeOffset) + offset; animation.Nodes.Add(new EAN_Node() { BoneName = GetBoneName(BitConverter.ToInt16(rawBytes, thisNodeOffset), animIndex, bonesNonHierachal) }); int keyframedAnimationsCount = BitConverter.ToInt16(rawBytes, thisNodeOffset + 2); int keyframedAnimationsOffset = BitConverter.ToInt32(rawBytes, thisNodeOffset + 4) + thisNodeOffset; if (keyframedAnimationsCount > 0) { animation.Nodes[i].AnimationComponents = new ObservableCollection <EAN_AnimationComponent>(); for (int a = 0; a < keyframedAnimationsCount; a++) { int thisKeyframedAnimationsOffset = BitConverter.ToInt32(rawBytes, keyframedAnimationsOffset) + thisNodeOffset; animation.Nodes[i].AnimationComponents.Add(new EAN_AnimationComponent()); animation.Nodes[i].AnimationComponents[a].I_00 = (EAN_AnimationComponent.ComponentType)rawBytes[thisKeyframedAnimationsOffset + 0]; animation.Nodes[i].AnimationComponents[a].I_01 = rawBytes[thisKeyframedAnimationsOffset + 1]; animation.Nodes[i].AnimationComponents[a].I_02 = BitConverter.ToInt16(rawBytes, thisKeyframedAnimationsOffset + 2); //Offsets/Count int keyframeCount = BitConverter.ToInt32(rawBytes, thisKeyframedAnimationsOffset + 4); int IndexListOffset = BitConverter.ToInt32(rawBytes, thisKeyframedAnimationsOffset + 8) + thisKeyframedAnimationsOffset; int MatrixOffset = BitConverter.ToInt32(rawBytes, thisKeyframedAnimationsOffset + 12) + thisKeyframedAnimationsOffset; animation.Nodes[i].AnimationComponents[a].Keyframes = ParseKeyframes(IndexListOffset, MatrixOffset, keyframeCount, indexSize, floatSize); keyframedAnimationsOffset += 4; } } nodeOffset += 4; } } animation.Name = Utils.GetString(bytes, nameOffset); animation.IndexNumeric = animIndex; return(animation); }
private void WriteAnimation(EAN_Animation animation, int offsetToReplace) { StartNewLine(); if (animation.FrameCount <= 0) { throw new InvalidDataException("EAN Save: FrameCount cannot be 0 or less!"); } bytes = Utils.ReplaceRange(bytes, BitConverter.GetBytes(bytes.Count()), offsetToReplace); int startOffset = bytes.Count(); int nodeCount = (animation.Nodes != null) ? animation.Nodes.Count() : 0; if (nodeCount > 0) { nodeCount = 0; for (int i = 0; i < animation.Nodes.Count(); i++) { if (eanFile.Skeleton.Exists(animation.Nodes[i].BoneName)) { nodeCount++; } } } bytes.AddRange(new byte[2]); bytes.Add((byte)animation.I_02); bytes.Add((byte)animation.I_03); bytes.AddRange(BitConverter.GetBytes(animation.FrameCount)); bytes.AddRange(BitConverter.GetBytes(nodeCount)); bytes.AddRange(new byte[4]); //Nodes if (nodeCount > 0) { bytes = Utils.ReplaceRange(bytes, BitConverter.GetBytes(bytes.Count - startOffset), startOffset + 12); List <int> NodeTable = new List <int>(); for (int i = 0; i < nodeCount; i++) { NodeTable.Add(bytes.Count); bytes.AddRange(new byte[4]); } for (int i = 0; i < nodeCount; i++) { if (eanFile.Skeleton.Exists(animation.Nodes[i].BoneName)) { bytes = Utils.ReplaceRange(bytes, BitConverter.GetBytes(bytes.Count - startOffset), NodeTable[i]); int NodeOffset = bytes.Count; List <int> AnimationComponentTable = new List <int>(); int AnimationComponentCount = (animation.Nodes[i].AnimationComponents != null) ? animation.Nodes[i].AnimationComponents.Count : 0; bytes.AddRange(BitConverter.GetBytes(GetBoneIndex(animation.Nodes[i].BoneName, animation.Name))); bytes.AddRange(BitConverter.GetBytes((short)AnimationComponentCount)); bytes.AddRange(BitConverter.GetBytes(8)); //Get ESK data for this bone as it will be needed for calculating default keyframes ESK_RelativeTransform eskRelativeTransform = eanFile.Skeleton.GetBone(animation.Nodes[i].BoneName)?.RelativeTransform; if (eskRelativeTransform == null) { throw new ArgumentNullException($"EAN Save: Could not find the RelativeTransform for bone {animation.Nodes[i].BoneName}"); } //Table for (int a = 0; a < AnimationComponentCount; a++) { AnimationComponentTable.Add(bytes.Count()); bytes.AddRange(new byte[4]); } //Data for (int a = 0; a < AnimationComponentCount; a++) { bytes = Utils.ReplaceRange(bytes, BitConverter.GetBytes(bytes.Count - NodeOffset), AnimationComponentTable[a]); int KeyframeOffset = bytes.Count; //Can happen if loaded from XML and no keyframes were declared. if (animation.Nodes[i].AnimationComponents[a].Keyframes == null) { animation.Nodes[i].AnimationComponents[a].Keyframes = AsyncObservableCollection <EAN_Keyframe> .Create(); } //Handle first and last keyframe bool hasFirstKeyframe = animation.Nodes[i].AnimationComponents[a].Keyframes.Any(x => x.FrameIndex == 0); bool hasFinalKeyframe = animation.Nodes[i].AnimationComponents[a].Keyframes.Any(x => x.FrameIndex == animation.FrameCount - 1); int KeyframeCount = animation.Nodes[i].AnimationComponents[a].Keyframes.Count; //If no first or final keyframes were found, increment count to include them if (!hasFinalKeyframe) { KeyframeCount++; } if (!hasFirstKeyframe) { KeyframeCount++; } //Select default keyframe EAN_Keyframe defaultKeyframe = null; switch (animation.Nodes[i].AnimationComponents[a].I_00) { case EAN_AnimationComponent.ComponentType.Position: defaultKeyframe = eskRelativeTransform.ToEanPosKeyframe(); break; case EAN_AnimationComponent.ComponentType.Rotation: defaultKeyframe = eskRelativeTransform.ToEanRotKeyframe(); break; case EAN_AnimationComponent.ComponentType.Scale: defaultKeyframe = eskRelativeTransform.ToEanScaleKeyframe(); break; } //Write bytes.Add((byte)animation.Nodes[i].AnimationComponents[a].I_00); bytes.Add(animation.Nodes[i].AnimationComponents[a].I_01); bytes.AddRange(BitConverter.GetBytes(animation.Nodes[i].AnimationComponents[a].I_02)); bytes.AddRange(BitConverter.GetBytes(KeyframeCount)); bytes.AddRange(new byte[8]); //Validate if (animation.Nodes[i].AnimationComponents[a].Keyframes.Any(x => x.FrameIndex > (animation.FrameCount - 1))) { throw new Exception($"EAN Save: Keyframe FrameIndex must not exceed the animation duration. (Name: {animation.Name}, ID: {animation.ID_UShort}"); } //Write Keyframes if (KeyframeCount > 0) { Sorting.SortEntries2(animation.Nodes[i].AnimationComponents[a].Keyframes); bytes = Utils.ReplaceRange(bytes, BitConverter.GetBytes(bytes.Count - KeyframeOffset), KeyframeOffset + 8); switch (animation.I_02) { case EAN_Animation.IntPrecision._8Bit: WriteKeyframeIndex_Int8(animation.Nodes[i].AnimationComponents[a].Keyframes, hasFirstKeyframe, hasFinalKeyframe, animation.FrameCount - 1); break; case EAN_Animation.IntPrecision._16Bit: WriteKeyframeIndex_Int16(animation.Nodes[i].AnimationComponents[a].Keyframes, hasFirstKeyframe, hasFinalKeyframe, animation.FrameCount - 1); break; } StartNewLine(); bytes = Utils.ReplaceRange(bytes, BitConverter.GetBytes(bytes.Count - KeyframeOffset), KeyframeOffset + 12); switch (animation.I_03) { case EAN_Animation.FloatPrecision._16Bit: WriteKeyframeFloats_Float16(animation.Nodes[i].AnimationComponents[a].Keyframes, hasFirstKeyframe, hasFinalKeyframe, defaultKeyframe); break; case EAN_Animation.FloatPrecision._32Bit: WriteKeyframeFloats_Float32(animation.Nodes[i].AnimationComponents[a].Keyframes, hasFirstKeyframe, hasFinalKeyframe, defaultKeyframe); break; } } } } } } bytes.AddRange(new byte[12]); }
private void WriteAnimation(EAN_Animation animation, int offsetToReplace) { StartNewLine(); bytes = Utils.ReplaceRange(bytes, BitConverter.GetBytes(bytes.Count()), offsetToReplace); int startOffset = bytes.Count(); int nodeCount = (animation.Nodes != null) ? animation.Nodes.Count() : 0; if (nodeCount > 0) { nodeCount = 0; for (int i = 0; i < animation.Nodes.Count(); i++) { if (eanFile.Skeleton.Exists(animation.Nodes[i].BoneName)) { nodeCount++; } } } bytes.AddRange(new byte[2]); bytes.Add((byte)animation.I_02); bytes.Add((byte)animation.I_03); bytes.AddRange(BitConverter.GetBytes(animation.I_04)); bytes.AddRange(BitConverter.GetBytes(nodeCount)); bytes.AddRange(new byte[4]); //Nodes if (nodeCount > 0) { bytes = Utils.ReplaceRange(bytes, BitConverter.GetBytes(bytes.Count() - startOffset), startOffset + 12); List <int> NodeTable = new List <int>(); for (int i = 0; i < nodeCount; i++) { NodeTable.Add(bytes.Count()); bytes.AddRange(new byte[4]); } for (int i = 0; i < nodeCount; i++) { if (eanFile.Skeleton.Exists(animation.Nodes[i].BoneName)) { bytes = Utils.ReplaceRange(bytes, BitConverter.GetBytes(bytes.Count() - startOffset), NodeTable[i]); int NodeOffset = bytes.Count(); List <int> AnimationComponentTable = new List <int>(); int AnimationComponentCount = (animation.Nodes[i].AnimationComponents != null) ? animation.Nodes[i].AnimationComponents.Count() : 0; bytes.AddRange(BitConverter.GetBytes(GetBoneIndex(animation.Nodes[i].BoneName, animation.Name))); bytes.AddRange(BitConverter.GetBytes((short)AnimationComponentCount)); bytes.AddRange(BitConverter.GetBytes(8)); //Table for (int a = 0; a < AnimationComponentCount; a++) { AnimationComponentTable.Add(bytes.Count()); bytes.AddRange(new byte[4]); } //Data for (int a = 0; a < AnimationComponentCount; a++) { bytes = Utils.ReplaceRange(bytes, BitConverter.GetBytes(bytes.Count() - NodeOffset), AnimationComponentTable[a]); int KeyframeOffset = bytes.Count(); int KeyframeCount = (animation.Nodes[i].AnimationComponents[a].Keyframes != null) ? animation.Nodes[i].AnimationComponents[a].Keyframes.Count() : 0; bytes.Add((byte)animation.Nodes[i].AnimationComponents[a].I_00); bytes.Add(animation.Nodes[i].AnimationComponents[a].I_01); bytes.AddRange(BitConverter.GetBytes(animation.Nodes[i].AnimationComponents[a].I_02)); bytes.AddRange(BitConverter.GetBytes(KeyframeCount)); bytes.AddRange(new byte[8]); //Sort Keyframes if (KeyframeCount > 0) { var sortedList = animation.Nodes[i].AnimationComponents[a].Keyframes.ToList(); sortedList.Sort((x, y) => x.FrameIndex - y.FrameIndex); animation.Nodes[i].AnimationComponents[a].Keyframes = new ObservableCollection <EAN_Keyframe>(sortedList); } if (KeyframeCount > 0) { bytes = Utils.ReplaceRange(bytes, BitConverter.GetBytes(bytes.Count() - KeyframeOffset), KeyframeOffset + 8); switch (animation.I_02) { case EAN_Animation.IntPrecision._8Bit: WriteKeyframeIndex_Int8(animation.Nodes[i].AnimationComponents[a].Keyframes); break; case EAN_Animation.IntPrecision._16Bit: WriteKeyframeIndex_Int16(animation.Nodes[i].AnimationComponents[a].Keyframes); break; } StartNewLine(); bytes = Utils.ReplaceRange(bytes, BitConverter.GetBytes(bytes.Count() - KeyframeOffset), KeyframeOffset + 12); switch (animation.I_03) { case EAN_Animation.FloatPrecision._16Bit: WriteKeyframeFloats_Float16(animation.Nodes[i].AnimationComponents[a].Keyframes); break; case EAN_Animation.FloatPrecision._32Bit: WriteKeyframeFloats_Float32(animation.Nodes[i].AnimationComponents[a].Keyframes); break; } } } } } } bytes.AddRange(new byte[12]); }