private void WriteKeyframeFloats_Float32(IList <EAN_Keyframe> keyframes, bool hasFirstKeyframe, bool hasFinalKeyframe, EAN_Keyframe defaultKeyframe) { if (!hasFirstKeyframe) { EAN_Keyframe defaultFirstKeyframe = (keyframes.Count == 0) ? defaultKeyframe : keyframes[0]; bytes.AddRange(BitConverter.GetBytes(defaultFirstKeyframe.X)); bytes.AddRange(BitConverter.GetBytes(defaultFirstKeyframe.Y)); bytes.AddRange(BitConverter.GetBytes(defaultFirstKeyframe.Z)); bytes.AddRange(BitConverter.GetBytes(defaultFirstKeyframe.W)); } for (int i = 0; i < keyframes.Count; i++) { bytes.AddRange(BitConverter.GetBytes(keyframes[i].X)); bytes.AddRange(BitConverter.GetBytes(keyframes[i].Y)); bytes.AddRange(BitConverter.GetBytes(keyframes[i].Z)); bytes.AddRange(BitConverter.GetBytes(keyframes[i].W)); } if (!hasFinalKeyframe) { EAN_Keyframe defaultFinalKeyframe = (keyframes.Count == 0) ? defaultKeyframe : keyframes[keyframes.Count - 1]; bytes.AddRange(BitConverter.GetBytes(defaultFinalKeyframe.X)); bytes.AddRange(BitConverter.GetBytes(defaultFinalKeyframe.Y)); bytes.AddRange(BitConverter.GetBytes(defaultFinalKeyframe.Z)); bytes.AddRange(BitConverter.GetBytes(defaultFinalKeyframe.W)); } }
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]); }