/// <summary> /// Get the animation clip in the format used to save and load clips. /// boneFilter is a list of bones to match that will be saved all other discarded /// leave null or empty to select all bones /// </summary> public static List<string> GetAnimationClipData(AnimationClip clip, bool isTypeClip, IDictionary<string, int> BoneMap, List<string> bonesFilter, float centreFrame) { // This is where we store the lines to export to the file List<string> data = new List<string>(); if (isTypeClip) { // CLIP // Add the details from the AnimationClip string output = ParseData.IntToString(clip.BoneCount) + " " + ParseData.TimeToString(clip.Duration); // Add the sound times for (int s = 0; s < clip.SoundFrameTimes.Count; s++) { output += " " + ParseData.TimeToString(clip.SoundFrameTimes[s]); } data.Add(output); } else { // PART, head or arms // Use the details from the AnimationClip to create the AnimationPart file // Add the extra header information for, max, min and defaultFrame data.Add(String.Format("{0} {1} {2} {3}", ParseData.IntToString(clip.BoneCount), ParseData.FloatToString(GlobalSettings.armAnimateAngleUp), ParseData.FloatToString(GlobalSettings.armAnimateAngleDown), ParseData.FloatToString(centreFrame))); } IList<Keyframe> frames = clip.Keyframes; if (frames == null) { data.Clear(); // Animation does not have any frames return null; } // Add each keyframe WantedBones BoneTest = new WantedBones(BoneMap, bonesFilter); for (int i = 0; i < frames.Count; i++) { // FRAME // Include some or all of the bones to create // either an AnimationClip or AnimationPart file if (BoneTest.IsBoneWeWant(frames[i].Bone)) { data.Add(String.Format("{0} {1}{2}{3}", ParseData.IntToString(frames[i].Bone), ParseData.TimeToString(frames[i].Time), ParseData.div, ParseData.MatrixToString(frames[i].Transform))); } } return data; }
// Convert each clip to a string array for saving // boneFilter is a list of bones to match that will be saved all other discarded // leave null or empty to select all bones public List<string> GetSaveClipData(AnimationClip clip, bool isTypeClip, IDictionary<string, int> boneMap, string clipName, List<string> bonesFilter, float centreFrame) { if (clip == null || boneMap == null) { form.AddMessageLine("Animation does not exist in the file: " + clipName); return null; } return ParseClips.GetAnimationClipData(clip, isTypeClip, boneMap, bonesFilter, centreFrame); }
public static AnimationClip MergeClips(AnimationClip upper, AnimationClip lower, IDictionary<string, int> BoneMap, List<string> upperBonesFilter) { // Only valid if both clips are for the same skeleton int boneCount = upper.BoneCount; if (lower.BoneCount != boneCount) { return null; } TimeSpan duration = lower.Duration; if (upper.Duration > lower.Duration) { duration = upper.Duration; } // The foot sounds only come from the lower bones. List<TimeSpan> steps = lower.SoundFrameTimes; IList<Keyframe> keyframes = new List<Keyframe>(); IList<Keyframe> upperframes = upper.Keyframes; IList<Keyframe> lowerframes = lower.Keyframes; WantedBones UpperBoneTest = new WantedBones(BoneMap, upperBonesFilter); int nextUpper = 0; int nextLower = 0; while (nextLower < lowerframes.Count) { while (nextUpper < upperframes.Count && upperframes[nextUpper].Time <= lowerframes[nextLower].Time) { if (UpperBoneTest.IsBoneWeWant(upperframes[nextUpper].Bone)) { keyframes.Add(upperframes[nextUpper]); } nextUpper++; } if (!UpperBoneTest.IsBoneWeWant(lowerframes[nextLower].Bone)) { keyframes.Add(lowerframes[nextLower]); } nextLower++; } // Add the remainder if (nextUpper < upperframes.Count) { for (int i = nextUpper; i < upperframes.Count; i++) { if (UpperBoneTest.IsBoneWeWant(upperframes[nextUpper].Bone)) { keyframes.Add(upperframes[i]); } } } return new AnimationClip(boneCount, duration, keyframes, steps); }
// Add a clip to the list and diplays it public void AddToClipList(AnimationClip clip, string name) { if (clip != null) { if (loadedClips.ContainsKey(name)) { // rename to avoid duplicates name += DateTime.Now.ToString(GlobalSettings.timeFormat); } clipNames.Add(name); loadedClips.Add(name, clip); currentClipName = name; string error = modelViewerControl.SetExternalClip(clip); SaveClipMenu.Enabled = true; if (!string.IsNullOrEmpty(error)) { AddMessageLine(error); DisplayTheBindPose(); } } else { AddMessageLine("No clip data!"); } HaveClipsLoaded(); }
// Returns the name of the saved file private string ClipSaveDialogue(AnimationClip clip, IDictionary<string, int> boneMap) { // Path to default location string pathToSaveFolder = defaultFileFolder; string assetName = ""; string fileName = currentClipName; // If we have loaded a file use that for the path and the name if (lastLoadedFile != "") { pathToSaveFolder = Path.GetDirectoryName(lastLoadedFile); assetName = Path.GetFileNameWithoutExtension(lastLoadedFile) + "-"; } // Append the name to the end of the filename fileName = assetName + fileName; SaveFileDialog fileDialog = new SaveFileDialog(); fileDialog.InitialDirectory = pathToSaveFolder; fileDialog.Title = "Save the animation clip"; fileDialog.FileName = fileName; fileDialog.Filter = "Clip File (*.clip)|*.clip|" + "Head File (*.head)|*.head|" + "Arms File (*.arms)|*.arms|" + "Pose File (*.pose)|*.pose|" + "Animation File Types (*.clip;*.arms;*.head;*.pose)|*.clip;*.arms;*.head;*.pose|" + "All Files (*.*)|*.*"; if (fileDialog.ShowDialog() == DialogResult.OK) { string fileType = Path.GetExtension(fileDialog.FileName).ToLower(); bool isClip = false; if (fileType == "clip" || fileType == ".clip" || fileType == "pose" || fileType == ".pose") { isClip = true; } List<string> data = ParseClips.GetAnimationClipData(clip, isClip, boneMap, currentBoneFilter, currentCentreFrame); if (data == null || data.Count < 1) { AddMessageLine("No clip data!"); return ""; } SaveTextFile(fileDialog.FileName, data); return fileDialog.FileName; } return ""; }
private void MergeAnimations(AnimationClip upper, AnimationClip lower, string mergeFilePath, List<string> upperBodyBones) { AnimationClip result = ParseClips.MergeClips(upper, lower, form.GetBoneMap(), upperBodyBones); List<string> data = ParseClips.GetAnimationClipData(result, true, null, null, 0); form.AddMessageLine("Saving: " + mergeFilePath); File.WriteAllLines(mergeFilePath, data); string name = Path.GetFileNameWithoutExtension(mergeFilePath); form.AddToClipList(result, name); }
// returns any error message public string SetExternalClip(AnimationClip clip) { if (isAnimated && model != null && animationPlayer != null) { // Change the animation return animationPlayer.StartClip(clip); } return "The model is not animated!"; }
/// <summary> /// Starts decoding the specified animation clip. /// Returns an error message /// </summary> public string StartClip(AnimationClip clip) { string error = ""; // Use a null clip to set the model to the bind pose if (clip != null && (skinningDataValue == null || clip.BoneCount != skinningDataValue.BoneMap.Count)) { error += "\nThe number of bones in the clip does not match the number in the model!"; return error; } currentClipValue = clip; currentTimeValue = TimeSpan.Zero; currentKeyframe = 0; // Initialize bone transforms to the bind pose. skinningDataValue.BindPose.CopyTo(boneTransforms, 0); return error; }