public void StartAnimation(SpriteRenderer renderer, AnimTrack animTrack, bool loop, float speed = 7) { if (_activeAnimations.TryGetValue(renderer, out Animation animation)) { animation.Speed = speed; animation.Loop = loop; animation.Sleeps = false; if (animation.AnimTrack != animTrack) { animation.AnimTrack = animTrack; animation.Sprites = _config.Sequences.Find(sequence => sequence.Track == animTrack).Sprites; animation.Counter = 0; } } else { _activeAnimations.Add(renderer, new Animation { AnimTrack = animTrack, Sprites = _config.Sequences.Find(sequence => sequence.Track == animTrack).Sprites, Speed = speed, Loop = loop }); } }
/// <summary> /// Reads the data out of the given track. /// </summary> /// <param name="track"></param> /// <returns></returns> public object[] ReadTrack(AnimTrack track) { //Console.WriteLine(Track.Name + " " + Track.Flags.ToString("X") + " " + Track.FrameCount + " " + Track.DataOffset.ToString("X")); List <object> output = new List <object>(); using (SsbhParser parser = new SsbhParser(new MemoryStream(animFile.Buffer))) { parser.Seek(track.DataOffset); if (CheckFlag(track.Flags, 0xFF00, AnimTrackFlags.Constant)) { output.Add(ReadDirect(parser, track.Flags)); } if (CheckFlag(track.Flags, 0xFF00, AnimTrackFlags.ConstTransform)) { // TODO: investigate more output.Add(ReadDirect(parser, track.Flags)); } if (CheckFlag(track.Flags, 0xFF00, AnimTrackFlags.Direct)) { for (int i = 0; i < track.FrameCount; i++) { output.Add(ReadDirect(parser, track.Flags)); } } if (CheckFlag(track.Flags, 0xFF00, AnimTrackFlags.Compressed)) { output.AddRange(ReadCompressed(parser, track.Flags)); } } return(output.ToArray()); }
protected Spine.Animation GetCurrentAnim(AnimTrack track) { if (CurrectTrackEntry(track) == null) { return(null); } return(CurrectTrackEntry(track).Animation); }
public ModelTimelineTrack(AnimTrack track) { keys = new List <Sce.Atf.Controls.Timelines.IKey>(); this.track = track; foreach (AnimKeyframe key in track.Keys) { keys.Add(new ModelTimelineKey(track, key)); } }
private static AnimTrack ParseTrack(FileReader reader, GameVersion version, long startPos, bool rotation = false) { long pos = reader.Position; uint Offset = reader.ReadUInt16(); if (Offset == 0) { return(new AnimTrack()); } reader.SeekBegin(startPos + Offset); var track = new AnimTrack(reader, version, rotation); reader.SeekBegin(pos + sizeof(ushort)); //Seek back to next offset return(track); }
/// <summary> /// Adds a track to be encoded /// </summary> /// <param name="NodeName">target material/texture/mesh name</param> /// <param name="TrackName">Usually "Transform" or "Visibility" matches <see cref="ANIM_TYPE"/></param> /// <param name="Type"><see cref="ANIM_TYPE"/></param> /// <param name="Values">Supported types AnimTrackTransform, AnimTrackTexture, AnimTrackCustomVector4, bool, float, int</param> public void AddTrack(string nodeName, string trackName, ANIM_TYPE type, IList <object> values) { AnimNode node = GetNode(type, nodeName); AnimTrack track = new AnimTrack { FrameCount = (uint)values.Count, Name = trackName }; var tracks = node.Tracks; Array.Resize(ref tracks, tracks.Length + 1); tracks[tracks.Length - 1] = track; node.Tracks = tracks; trackToValues.Add(track, values); }
public void Read(FileReader reader, GameVersion version) { long pos = reader.Position; reader.ReadSignature(4, "anod"); BoneIndex = reader.ReadUInt16(); RotationFlags = reader.ReadUInt16(); TranslateX = ParseTrack(reader, version, pos); TranslateY = ParseTrack(reader, version, pos); TranslateZ = ParseTrack(reader, version, pos); RotationX = ParseTrack(reader, version, pos, RotationFlags == 1); RotationY = ParseTrack(reader, version, pos, RotationFlags == 1); RotationZ = ParseTrack(reader, version, pos, RotationFlags == 1); ScaleX = ParseTrack(reader, version, pos); ScaleY = ParseTrack(reader, version, pos); ScaleZ = ParseTrack(reader, version, pos); reader.ReadUInt16();//0x00 }
private bool AnimationLock(AnimTrack track) { if (GetCurrentAnim(track) == null) { return(false); } switch (GetCurrentAnim(track).Name) { case Anim.TAKING_OFF: case Anim.ATTACK_STRONG_STATIC: case Anim.ATTACK_STRONG_MOVING: case Anim.MOVE_JUMPING: case Anim.INTERACT_LOOT: DebugUI.Flash_AnimBlock(); return(true); default: return(false); } }
// private void InitObjects() { m_EditableObjects = null; Object[] activeGOs = Selection.GetFiltered(typeof(Animation), SelectionMode.Editable | SelectionMode.TopLevel); if (activeGOs.Length > 0) { m_EditableObjects = new AnimTrack[activeGOs.Length]; int index = 0; foreach (Object obj in activeGOs) { AnimTrack aTrack = new AnimTrack(((Animation)obj).gameObject); if (aTrack.m_Animation) { m_MaxSliderTime = Mathf.Max(m_MaxSliderTime, aTrack.m_Animation.length); } m_EditableObjects[index++] = aTrack; } } }
protected void ClearAnim(AnimTrack track) { AnimationState.ClearTrack((int)track); }
public object[] ReadTrack(AnimTrack Track) { Console.WriteLine(Track.Name + " " + Track.Flags.ToString() + " " + Track.FrameCount + " " + Track.DataOffset.ToString("X")); List <object> output = new List <object>(); using (SSBHParser parser = new SSBHParser(new MemoryStream(AnimFile.Buffer))) { parser.Seek(Track.DataOffset); if (CheckFlag(Track.Flags, 0x00FF, ANIM_TRACKFLAGS.Boolean)) { if (CheckFlag(Track.Flags, 0xFF00, ANIM_TRACKFLAGS.Animated)) { int Unk_4 = parser.ReadInt16(); int TrackFlag = parser.ReadInt16(); int Unk1 = parser.ReadInt16(); int Unk2 = parser.ReadInt16(); int DataStart = parser.ReadInt32(); int FrameCount = parser.ReadInt32(); parser.Seek((int)Track.DataOffset + DataStart); for (int i = 0; i < FrameCount; i++) { output.Add(new AnimTrackBool(parser.ReadBits(1) == 1)); } } else if (CheckFlag(Track.Flags, 0xFF00, ANIM_TRACKFLAGS.Constant)) { output.Add(new AnimTrackBool(parser.ReadBits(1) == 1)); } } if (CheckFlag(Track.Flags, 0x00FF, ANIM_TRACKFLAGS.Vector4)) { if (CheckFlag(Track.Flags, 0xFF00, ANIM_TRACKFLAGS.Animated)) { int Unk_4 = parser.ReadInt16(); int TrackFlag = parser.ReadInt16(); int Unk1 = parser.ReadInt16(); int Unk2 = parser.ReadInt16(); int DataStart = parser.ReadInt32(); int FrameCount = parser.ReadInt32(); int[] ByteCounts = new int[9]; int[] BitCounts = new int[9]; float[] Start = new float[9]; float[] End = new float[9]; for (int i = 0; i < 4; i++) { Start[i] = parser.ReadSingle(); End[i] = parser.ReadSingle(); long Count = parser.ReadInt64(); long bytes = (Count >> 3); int bits = ((int)Count & 0x7); if ((i >= 0 && i <= 0 && (TrackFlag & 0x3) == 0x3) || //isotrophic scale (i >= 0 && i <= 2 && (TrackFlag & 0x3) == 0x1) || //normal scale (i > 2 && i <= 5 && (TrackFlag & 0x4) > 0) || (i > 5 && i <= 8 && (TrackFlag & 0x8) > 0)) { //reads { BitCounts[i] = bits; ByteCounts[i] = (int)bytes; } } } float X = parser.ReadSingle(); float Y = parser.ReadSingle(); float Z = parser.ReadSingle(); float W = parser.ReadSingle(); parser.Seek((int)Track.DataOffset + DataStart); for (int i = 0; i < FrameCount; i++) { AnimTrackCustomVector4 Vector = new AnimTrackCustomVector4(); for (int j = 0; j < 4; j++) { int ValueBitCount = ByteCounts[j] * 8 + BitCounts[j]; int Value = parser.ReadBits(ValueBitCount); int scale = 0; for (int k = 0; k < ValueBitCount; k++) { scale |= 0x1 << k; } float FrameValue = Lerp(Start[j], End[j], 0, 1, Value / (float)scale); if (float.IsNaN(FrameValue)) { FrameValue = 0; } switch (j) { case 0: if (ValueBitCount > 0) { Vector.X = FrameValue; } else { Vector.X = X; } break; case 1: if (ValueBitCount > 0) { Vector.Y = FrameValue; } else { Vector.Y = Y; } break; case 2: if (ValueBitCount > 0) { Vector.Z = FrameValue; } else { Vector.Z = Z; } break; case 3: if (ValueBitCount > 0) { Vector.W = FrameValue; } else { Vector.W = W; } break; } } output.Add(Vector); } } else if (CheckFlag(Track.Flags, 0xFF00, ANIM_TRACKFLAGS.Constant)) { output.Add(new AnimTrackCustomVector4() { X = parser.ReadSingle(), Y = parser.ReadSingle(), Z = parser.ReadSingle(), W = parser.ReadSingle() }); } } if (CheckFlag(Track.Flags, 0x00FF, ANIM_TRACKFLAGS.Transform)) { if (CheckFlag(Track.Flags, 0xFF00, ANIM_TRACKFLAGS.Animated)) { int Unk_4 = parser.ReadInt16(); int TrackFlag = parser.ReadInt16(); int Unk1 = parser.ReadInt16(); int Unk2 = parser.ReadInt16(); int DataStart = parser.ReadInt32(); int FrameCount = parser.ReadInt32(); int[] ByteCounts = new int[9]; int[] BitCounts = new int[9]; float[] Start = new float[9]; float[] End = new float[9]; for (int i = 0; i < 9; i++) { Start[i] = parser.ReadSingle(); End[i] = parser.ReadSingle(); long Count = parser.ReadInt64(); long bytes = (Count >> 3); int bits = ((int)Count & 0x7); if ((i >= 0 && i <= 0 && (TrackFlag & 0x3) == 0x3) || //isotrophic scale (i >= 0 && i <= 2 && (TrackFlag & 0x3) == 0x1) || //normal scale (i > 2 && i <= 5 && (TrackFlag & 0x4) > 0) || (i > 5 && i <= 8 && (TrackFlag & 0x8) > 0)) { //reads { BitCounts[i] = bits; ByteCounts[i] = (int)bytes; } } } float XSCA = parser.ReadSingle(); float YSCA = parser.ReadSingle(); float ZSCA = parser.ReadSingle(); float XROT = parser.ReadSingle(); float YROT = parser.ReadSingle(); float ZROT = parser.ReadSingle(); float WROT = parser.ReadSingle(); float XPOS = parser.ReadSingle(); float YPOS = parser.ReadSingle(); float ZPOS = parser.ReadSingle(); parser.ReadInt32(); // ???? parser.Seek((int)Track.DataOffset + DataStart); for (int i = 0; i < FrameCount; i++) { AnimTrackTransform Transform = new AnimTrackTransform(); for (int j = 0; j < 9; j++) { int ValueBitCount = ByteCounts[j] * 8 + BitCounts[j]; int Value = parser.ReadBits(ValueBitCount); int scale = 0; for (int k = 0; k < ValueBitCount; k++) { scale |= 0x1 << k; } float FrameValue = Lerp(Start[j], End[j], 0, 1, Value / (float)scale); if (float.IsNaN(FrameValue)) { FrameValue = 0; } if ((TrackFlag & 0x3) == 0x3) { //Scale Isotropic if (j == 0) { Transform.SX = FrameValue; Transform.SY = FrameValue; Transform.SZ = FrameValue; } } else if ((TrackFlag & 0x3) == 0x1) { //Scale normal switch (j) { case 0: if (ValueBitCount > 0) { Transform.SX = FrameValue; } else { Transform.SX = XSCA; } break; case 1: if (ValueBitCount > 0) { Transform.SY = FrameValue; } else { Transform.SY = YSCA; } break; case 2: if (ValueBitCount > 0) { Transform.SZ = FrameValue; } else { Transform.SZ = ZSCA; } break; } } else { Transform.SX = XSCA; Transform.SY = YSCA; Transform.SZ = ZSCA; } //Rotation if ((TrackFlag & 0x4) > 0) { switch (j) { case 3: if (ValueBitCount > 0) { Transform.RX = FrameValue; } else { Transform.RX = XROT; } break; case 4: if (ValueBitCount > 0) { Transform.RY = FrameValue; } else { Transform.RY = YROT; } break; case 5: if (ValueBitCount > 0) { Transform.RZ = FrameValue; } else { Transform.RZ = ZROT; } break; } } else { Transform.RX = XROT; Transform.RY = YROT; Transform.RZ = ZROT; Transform.RW = WROT; } // Position if ((TrackFlag & 0x8) > 0) { switch (j) { case 6: if (ValueBitCount > 0) { Transform.X = FrameValue; } else { Transform.X = XPOS; } break; case 7: if (ValueBitCount > 0) { Transform.Y = FrameValue; } else { Transform.Y = YPOS; } break; case 8: if (ValueBitCount > 0) { Transform.Z = FrameValue; } else { Transform.Z = ZPOS; } break; } } else { Transform.X = XPOS; Transform.Y = YPOS; Transform.Z = ZPOS; } } if ((TrackFlag & 0x4) > 0) { // Rotation w bool Wflip = parser.ReadBits(1) == 1;// (TrackFlag & 0x1) == 0 ? parser.ReadBits(1) == 1 : true; Transform.RW = (float)Math.Sqrt(Math.Abs(1 - (Transform.RX * Transform.RX + Transform.RY * Transform.RY + Transform.RZ * Transform.RZ))); if (Wflip) { Transform.RW = -Transform.RW; } } output.Add(Transform); } } else if (CheckFlag(Track.Flags, 0xFF00, ANIM_TRACKFLAGS.ConstTransform)) { output.Add(new AnimTrackTransform() { SX = parser.ReadSingle(), SY = parser.ReadSingle(), SZ = parser.ReadSingle(), RX = parser.ReadSingle(), RY = parser.ReadSingle(), RZ = parser.ReadSingle(), RW = parser.ReadSingle(), X = parser.ReadSingle(), Y = parser.ReadSingle(), Z = parser.ReadSingle(), }); parser.ReadInt32(); // ???? } } } return(output.ToArray()); }
protected TrackEntry AddAnim(AnimTrack track, string name, bool loop, float delay = -1) { return(AnimationState.AddAnimation((int)track, name, loop, delay != -1 ? delay : (CurrectTrackEntry(track) != null ? CurrectTrackEntry(track).MixDuration : 0F))); }
protected TrackEntry AddAnimEmpty(AnimTrack track, float mixDuration, float delay = -1) { return(AnimationState.AddEmptyAnimation((int)track, mixDuration, delay != -1 ? delay : (CurrectTrackEntry(track) != null ? CurrectTrackEntry(track).MixDuration : 0F))); }
public ModelTimelineKey(AnimTrack track) { this.track = track; }
private void ReadFrameData(DataReader d, int offset, int count, uint dataOffset, int boneCount, AnimTrack Track) { for (int i = offset; i < offset + count; i++) { d.Seek((uint)(dataOffset + 4 * 4 * i)); var flagOffset = d.ReadUInt32(); var keyFrameOffset = d.ReadUInt32(); var keyDataOffset = d.ReadUInt32(); d.Seek(flagOffset); var boneIndex = d.ReadInt16(); var keyFrameCount = d.ReadByte(); var flag = d.ReadByte(); var node = anim.TransformNodes[boneIndex + (flag == 0 ? boneCount : 0)]; d.Seek(keyDataOffset); for (int k = 0; k < keyFrameCount; k++) { var temp = d.Position; d.Seek((uint)(keyFrameOffset + k * 2)); var frame = d.ReadInt16(); d.Seek(temp); float[] animdata = new float[Track.DataCount]; for (int j = 0; j < Track.DataCount; j++) { switch (Track.DataType) { case 1: animdata[j] = d.ReadInt16() / (float)short.MaxValue; break; case 2: animdata[j] = d.ReadSingle(); break; case 4: animdata[j] = d.ReadInt16(); break; default: throw new NotImplementedException("Data Type " + Track.DataType + " not implemented"); } } switch (Track.Type) { case 1: node.AddKey(frame, animdata[0], AnimationTrackFormat.TranslateX); node.AddKey(frame, animdata[1], AnimationTrackFormat.TranslateY); node.AddKey(frame, animdata[2], AnimationTrackFormat.TranslateZ); break; case 2: var e = GenericBone.ToEulerAngles(new OpenTK.Quaternion(animdata[0], animdata[1], animdata[2], animdata[3]).Inverted()); node.AddKey(frame, e.X, AnimationTrackFormat.RotateX); node.AddKey(frame, e.Y, AnimationTrackFormat.RotateY); node.AddKey(frame, e.Z, AnimationTrackFormat.RotateZ); break; case 3: node.AddKey(frame, animdata[0], AnimationTrackFormat.ScaleX); node.AddKey(frame, animdata[1], AnimationTrackFormat.ScaleY); node.AddKey(frame, animdata[2], AnimationTrackFormat.ScaleZ); break; } } } }
public AnimTrackData(AnimTrack track, SsbhAnimTrackDecoder decoder) { Name = track.Name; Values = decoder.ReadTrack(track); }
protected TrackEntry CurrectTrackEntry(AnimTrack track) { return(AnimationState.GetCurrent((int)track)); }
public List <AnimSequence> GetAnimSequences() { var animSeqs = new List <AnimSequence>(); List <string> boneNames = Bones.Select(b => b.Name).ToList(); int boneCount = boneNames.Count; foreach (var info in Infos) { var seq = new AnimSequence { Bones = boneNames, Name = info.Name, NumFrames = info.NumRawFrames, SequenceLength = info.TrackTime / info.AnimRate, RateScale = 1, RawAnimationData = new List <AnimTrack>() }; for (int boneIdx = 0; boneIdx < boneCount; boneIdx++) { var track = new AnimTrack { Positions = new List <Vector3>(), Rotations = new List <Quaternion>() }; for (int frameIdx = 0; frameIdx < seq.NumFrames; frameIdx++) { int srcIdx = ((info.FirstRawFrame + frameIdx) * boneCount) + boneIdx; var posVec = Keys[srcIdx].Position; var rotQuat = Keys[srcIdx].Rotation; track.Positions.Add(new Vector3(posVec.X, posVec.Y * -1, posVec.Z)); track.Rotations.Add(new Quaternion(rotQuat.X, rotQuat.Y * -1, rotQuat.Z, rotQuat.W * -1)); } //if all keys are identical, replace with a single key if (track.Positions.Count > 1) { var firstKey = track.Positions[0]; if (track.Positions.TrueForAll(key => key == firstKey)) { track.Positions.Clear(); track.Positions.Add(firstKey); } } if (track.Rotations.Count > 1) { var firstKey = track.Rotations[0]; if (track.Rotations.TrueForAll(key => key == firstKey)) { track.Rotations.Clear(); track.Rotations.Add(firstKey); } } seq.RawAnimationData.Add(track); } animSeqs.Add(seq); } return(animSeqs); }
//All Animsequences MUST have the same BoneLists! public static PSA CreateFrom(List <AnimSequence> animSeqs) { if (animSeqs == null) { throw new ArgumentNullException(nameof(animSeqs)); } if (animSeqs.Count == 0) { throw new ArgumentException("No AnimSequences!", nameof(animSeqs)); } var psa = new PSA { Bones = new List <PSABone>(), Infos = new List <PSAAnimInfo>(), Keys = new List <PSAAnimKeys>() }; int numBones = animSeqs[0].Bones.Count; for (int i = 0; i < numBones; i++) { psa.Bones.Add(new PSABone { Name = animSeqs[0].Bones[i], ParentIndex = i == 0 ? -1 : 0 }); } int frameCount = 0; foreach (AnimSequence animSeq in animSeqs) { int numFrames = animSeq.NumFrames; psa.Infos.Add(new PSAAnimInfo { Name = animSeq.Name.Instanced, Group = "None", TotalBones = numBones, KeyQuotum = numBones * numFrames, TrackTime = numFrames, AnimRate = animSeq.NumFrames / animSeq.SequenceLength * animSeq.RateScale, FirstRawFrame = frameCount, NumRawFrames = numFrames }); frameCount += numFrames; if (animSeq.RawAnimationData is null) { animSeq.DecompressAnimationData(); } for (int frameIdx = 0; frameIdx < numFrames; frameIdx++) { for (int boneIdx = 0; boneIdx < numBones; boneIdx++) { AnimTrack animTrack = animSeq.RawAnimationData[boneIdx]; Vector3 posVec = animTrack.Positions.Count > frameIdx ? animTrack.Positions[frameIdx] : animTrack.Positions[animTrack.Positions.Count - 1]; Quaternion rotQuat = animTrack.Rotations.Count > frameIdx ? animTrack.Rotations[frameIdx] : animTrack.Rotations[animTrack.Rotations.Count - 1]; rotQuat = new Quaternion(rotQuat.X, rotQuat.Y * -1, rotQuat.Z, rotQuat.W * -1); posVec = new Vector3(posVec.X, posVec.Y * -1, posVec.Z); psa.Keys.Add(new PSAAnimKeys { Position = posVec, Rotation = rotQuat, Time = 1 }); } } } return(psa); }
public ModelTimelineKey(AnimTrack track, AnimKeyframe key) { this.key = key; this.track = track; }
protected TrackEntry SetAnim(AnimTrack track, string name, bool loop) { return(AnimationState.SetAnimation((int)track, name, loop)); }
protected TrackEntry SetAnimEmpty(AnimTrack track, float mixDuration) { return(AnimationState.SetEmptyAnimation((int)track, mixDuration)); }
public void DecompressAnimationData() { var ms = new MemoryStream(CompressedAnimationData); RawAnimationData = new List <AnimTrack>(); for (int i = 0; i < Bones.Count; i++) { int posOff = TrackOffsets[i * 4]; int numPosKeys = TrackOffsets[i * 4 + 1]; int rotOff = TrackOffsets[i * 4 + 2]; int numRotKeys = TrackOffsets[i * 4 + 3]; var track = new AnimTrack { Positions = new List <Vector3>(numPosKeys), Rotations = new List <Quaternion>(numRotKeys) }; if (numPosKeys > 0) { ms.JumpTo(posOff); AnimationCompressionFormat compressionFormat = posCompression; if (numPosKeys == 1) { compressionFormat = AnimationCompressionFormat.ACF_None; } for (int j = 0; j < numPosKeys; j++) { switch (compressionFormat) { case AnimationCompressionFormat.ACF_None: case AnimationCompressionFormat.ACF_Float96NoW: track.Positions.Add(new Vector3(ms.ReadFloat(), ms.ReadFloat(), ms.ReadFloat())); break; case AnimationCompressionFormat.ACF_IntervalFixed32NoW: case AnimationCompressionFormat.ACF_Fixed48NoW: case AnimationCompressionFormat.ACF_Fixed32NoW: case AnimationCompressionFormat.ACF_Float32NoW: case AnimationCompressionFormat.ACF_BioFixed48: throw new NotImplementedException($"Translation keys in format {compressionFormat} cannot be read yet!"); } } if (keyEncoding == AnimationKeyFormat.AKF_VariableKeyLerp && numPosKeys > 1) { ms.JumpTo(ms.Position.Align(4)); var keyTimes = new List <int>(numPosKeys); for (int j = 0; j < numPosKeys; j++) { keyTimes.Add(NumFrames > 0xFF ? ms.ReadUInt16() : ms.ReadByte()); } //RawAnimationData should have either 1 key, or the same number of keys as frames. //Lerp any missing keys List <Vector3> tempPositions = track.Positions; track.Positions = new List <Vector3>(NumFrames) { tempPositions[0] }; for (int frameIdx = 1, keyIdx = 1; frameIdx < NumFrames; keyIdx++, frameIdx++) { if (keyIdx >= keyTimes.Count) { track.Positions.Add(track.Positions[frameIdx - 1]); } else if (keyTimes[keyIdx] == frameIdx) { track.Positions.Add(tempPositions[keyIdx]); } else { int nextFrame = keyTimes[keyIdx]; int prevFrame = frameIdx - 1; for (int j = frameIdx; j < nextFrame; j++) { float amount = (float)(j - prevFrame) / (nextFrame - prevFrame); track.Positions.Add(Vector3.Lerp(track.Positions[prevFrame], tempPositions[keyIdx], amount)); } track.Positions.Add(tempPositions[keyIdx]); frameIdx = nextFrame; } } } } if (numRotKeys > 0) { ms.JumpTo(rotOff); AnimationCompressionFormat compressionFormat = rotCompression; if (numRotKeys == 1) { compressionFormat = AnimationCompressionFormat.ACF_Float96NoW; } else if (compressedDataSource != MEGame.UDK) { ms.Skip(12 * 2); //skip mins and ranges } for (int j = 0; j < numRotKeys; j++) { switch (compressionFormat) { case AnimationCompressionFormat.ACF_None: track.Rotations.Add(new Quaternion(ms.ReadFloat(), ms.ReadFloat(), ms.ReadFloat(), ms.ReadFloat())); break; case AnimationCompressionFormat.ACF_Float96NoW: { float x = ms.ReadFloat(); float y = ms.ReadFloat(); float z = ms.ReadFloat(); track.Rotations.Add(new Quaternion(x, y, z, getW(x, y, z))); break; } case AnimationCompressionFormat.ACF_BioFixed48: { const float shift = 0.70710678118f; const float scale = 1.41421356237f; const float precisionMult = 32767.0f; ushort a = ms.ReadUInt16(); ushort b = ms.ReadUInt16(); ushort c = ms.ReadUInt16(); float x = (a & 0x7FFF) / precisionMult * scale - shift; float y = (b & 0x7FFF) / precisionMult * scale - shift; float z = (c & 0x7FFF) / precisionMult * scale - shift; float w = getW(x, y, z); int wPos = ((a >> 14) & 2) | ((b >> 15) & 1); track.Rotations.Add(wPos switch { 0 => new Quaternion(w, x, y, z), 1 => new Quaternion(x, w, y, z), 2 => new Quaternion(x, y, w, z), _ => new Quaternion(x, y, z, w) }); break; }
/// <summary> /// /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void panel1_Paint(object sender, PaintEventArgs e) { e.Graphics.FillRectangle(backBrush, e.ClipRectangle); var graphOffsetX = 50; var graphOffsetY = 12; var graphWidth = panel1.Width - graphOffsetX; var graphHeight = panel1.Height - graphOffsetY; float ampHi = float.MinValue; float ampLw = float.MaxValue; var keyCount = (float)KeyFrames.Count; var spaces = (int)(keyCount / (graphWidth / TextRenderer.MeasureText(keyCount.ToString(), numFont).Width)); if (spaces < 1) { spaces = 1; } if (spaces % 5 != 0) { spaces += 5 - (spaces % 5); } AnimTrack a = new AnimTrack(); a.Keys = GetFOBJKeys(); for (int i = 0; i < KeyFrames.Count; i++) { var v = a.GetValue(i); ampHi = Math.Max(ampHi, v); ampLw = Math.Min(ampLw, v); } var dis = ampHi - ampLw; var off = dis * 0.15f; if (dis == 0) { return; } dis = (ampHi - ampLw) + off * 2; e.Graphics.DrawString(ampHi.ToString("0.0000"), numFont, numBrush, new PointF(0, (off / dis) * graphHeight - 4 + graphOffsetY)); e.Graphics.DrawString(ampLw.ToString("0.0000"), numFont, numBrush, new PointF(0, ((dis - off) / dis) * graphHeight - 4 + graphOffsetY)); e.Graphics.DrawLine(faintLinePen, new PointF(graphOffsetX, (off / dis) * graphHeight + graphOffsetY), new PointF(panel1.Width, (off / dis) * graphHeight + graphOffsetY)); e.Graphics.DrawLine(faintLinePen, new PointF(graphOffsetX, ((dis - off) / dis) * graphHeight + graphOffsetY), new PointF(panel1.Width, ((dis - off) / dis) * graphHeight + graphOffsetY)); for (int i = 1; i <= KeyFrames.Count; i++) { var x1 = graphOffsetX + (int)(((i - 1) / keyCount) * graphWidth); var h1 = (int)((a.GetValue(i - 1) + Math.Abs(ampLw) + off) / dis * graphHeight); var h2 = (int)((a.GetValue(i) + Math.Abs(ampLw) + off) / dis * graphHeight); if (i - 1 < KeyFrames.Count) { if (KeyFrames[i - 1].InterpolationType == GXInterpolationType.HSD_A_OP_CON) { h2 = h1; } } if (((i - 1) % spaces) == 0) { e.Graphics.DrawLine(faintLinePen, new Point(x1, graphOffsetY), new Point(x1, panel1.Height)); e.Graphics.DrawString((i - 1).ToString(), numFont, numBrush, new PointF(x1 - 4, 0)); } var px1 = graphOffsetX + (int)(((i - 1) / keyCount) * graphWidth); var px2 = graphOffsetX + (int)((i / keyCount) * graphWidth); var py1 = panel1.Height - h1; var py2 = panel1.Height - h2; e.Graphics.DrawLine(linePen, new Point(px1, py1), new Point(px2, py2)); if (i - 1 < KeyFrames.Count) { if (KeyFrames[i - 1].InterpolationType != GXInterpolationType.HSD_A_OP_NONE) { e.Graphics.FillRectangle(pointBrush, new RectangleF(px1 - 2, py1 - 2, 4, 4)); } } } }