private async Task GenerateBones() { this.Generating = true; await Dispatch.MainThread(); this.Bones.Clear(); if (this.Actor?.ModelObject?.Skeleton?.Skeleton == null) { return; } SkeletonViewModel skeletonVm = this.Actor.ModelObject.Skeleton.Skeleton; ////TemplateSkeleton template = skeletonVm.GetTemplate(this.Actor); await this.Generate(skeletonVm); // Map eyes together if they exist BoneVisual3d?lEye = this.GetBone("EyeLeft"); BoneVisual3d?rEye = this.GetBone("EyeRight"); if (lEye != null && rEye != null) { lEye.LinkedEye = rEye; rEye.LinkedEye = lEye; } foreach (BoneVisual3d bone in this.Bones) { bone.ReadTransform(); } foreach (BoneVisual3d bone in this.Bones) { bone.ReadTransform(); } this.Generating = false; }
public static SkeletonFile?GetSkeletonFile(this SkeletonViewModel self, ActorViewModel actor) { int maxDepth = int.MinValue; SkeletonFile?maxSkel = null; foreach (SkeletonFile template in PoseService.BoneNameFiles) { if (template.IsValid(self, actor)) { if (template.Depth > maxDepth) { maxDepth = template.Depth; maxSkel = template; } } } if (maxSkel != null) { return(maxSkel); } return(null); }
public async Task Apply(ActorViewModel actor, SkeletonVisual3d skeleton, Configuration config) { if (actor == null) { throw new ArgumentNullException(nameof(actor)); } if (actor.ModelObject == null) { throw new Exception("Actor has no model"); } if (actor.ModelObject.Skeleton == null) { throw new Exception("Actor model has no skeleton wrapper"); } if (actor.ModelObject.Skeleton.Skeleton == null) { throw new Exception("Actor skeleton wrapper has no skeleton"); } SkeletonViewModel skeletonMem = actor.ModelObject.Skeleton.Skeleton; skeletonMem.MemoryMode = MemoryModes.None; PoseService.Instance.SetEnabled(true); PoseService.Instance.CanEdit = false; await Task.Delay(100); if (this.Bones != null) { // Apply all transforms a few times to ensure parent-inherited values are caluclated correctly, and to ensure // we dont end up with some values read during a ffxiv frame update. for (int i = 0; i < 3; i++) { foreach ((string name, Bone? savedBone) in this.Bones) { if (savedBone == null) { continue; } BoneVisual3d?bone = skeleton.GetBone(name); if (bone == null) { Log.Warning($"Bone: \"{name}\" not found"); continue; } if (config.UseSelection && !skeleton.GetIsBoneSelected(bone)) { continue; } TransformPtrViewModel vm = bone.ViewModel; if (PoseService.Instance.FreezePositions && savedBone.Position != null && config.LoadPositions) { vm.Position = (Vector)savedBone.Position; } if (PoseService.Instance.FreezeRotation && savedBone.Rotation != null && config.LoadRotations) { vm.Rotation = (Quaternion)savedBone.Rotation; } if (PoseService.Instance.FreezeScale && savedBone.Scale != null && config.LoadScales) { vm.Scale = (Vector)savedBone.Scale; } bone.ReadTransform(); bone.WriteTransform(skeleton, false); } await Task.Delay(1); } } await Task.Delay(100); skeletonMem.MemoryMode = MemoryModes.ReadWrite; await skeletonMem.ReadFromMemoryAsync(); PoseService.Instance.CanEdit = true; }
private async Task Generate(SkeletonViewModel memory) { SkeletonFile?skeletonFile = memory.GetSkeletonFile(this.Actor); bool autoSkeleton = false; if ((skeletonFile == null || skeletonFile.Parenting == null) && GposeService.Instance.IsGpose) { string message = LocalizationService.GetStringFormatted("Pose_GenerateSkeleton", this.Actor.DisplayName); bool? result = await GenericDialog.Show(message, LocalizationService.GetString("Pose_GenerateSkeletonTitle"), MessageBoxButton.YesNo); autoSkeleton = result == true; } // Get all bones this.Bones.Clear(); this.GetBones(memory.Body, "Body"); this.GetBones(memory.Head, "Head"); this.GetBones(memory.Hair, "Hair"); this.GetBones(memory.Met, "Met"); this.GetBones(memory.Top, "Top"); if (skeletonFile != null && skeletonFile.BoneNames != null) { foreach (BoneVisual3d bone in this.Bones) { string?newName; if (skeletonFile.BoneNames.TryGetValue(bone.BoneName, out newName)) { bone.BoneName = newName; } } } if (autoSkeleton) { try { // gnerate parenting await ParentingUtility.ParentBones(this, this.Bones); } catch (Exception ex) { Log.Write(Severity.Error, new Exception("Failed to generate skeleton file.", ex)); return; } if (skeletonFile == null) { skeletonFile = new SkeletonFile(); skeletonFile.ModelType = this.Actor.ModelType; skeletonFile.Race = this.Actor.Customize?.Race; } skeletonFile.Parenting = new Dictionary <string, string>(); foreach (BoneVisual3d bone in this.Bones) { if (bone.Parent == null) { continue; } skeletonFile.Parenting.Add(bone.BoneName, bone.Parent.BoneName); } PoseService.SaveTemplate(skeletonFile); } else if (skeletonFile != null && skeletonFile.Parenting != null) { // parenting from file foreach (BoneVisual3d bone in this.Bones) { string?parentBoneName; if (skeletonFile.Parenting.TryGetValue(bone.BoneName, out parentBoneName)) { bone.Parent = this.GetBone(parentBoneName); if (bone.Parent == null) { throw new Exception($"Failed to find target parent bone: {parentBoneName}"); } } else { this.Children.Add(bone); } } } else { // no parenting... PoseService.Instance.EnableParenting = false; foreach (BoneVisual3d bone in this.Bones) { this.Children.Add(bone); } } }
public async Task Apply(ActorViewModel actor, SkeletonVisual3d skeleton, Configuration config, bool selectionOnly) { if (actor == null) { throw new ArgumentNullException(nameof(actor)); } if (actor.ModelObject == null) { throw new Exception("Actor has no model"); } if (actor.ModelObject.Skeleton == null) { throw new Exception("Actor model has no skeleton wrapper"); } if (actor.ModelObject.Skeleton.Skeleton == null) { throw new Exception("Actor skeleton wrapper has no skeleton"); } SkeletonViewModel skeletonMem = actor.ModelObject.Skeleton.Skeleton; skeletonMem.MemoryMode = MemoryModes.None; PoseService.Instance.SetEnabled(true); PoseService.Instance.CanEdit = false; await Task.Delay(100); // Facial expressions hack: // Since all facial bones are parented to the head, if we load the head rotation from // the pose that matches the expression, it wont break. // We then just set the head back to where it should be afterwards. BoneVisual3d?headBone = skeleton.GetIsHeadSelection() ? skeleton.GetBone("Head") : null; headBone?.ReadTransform(true); Quaternion?originalHeadRotation = headBone?.ViewModel.Rotation; if (this.Bones != null) { // Apply all transforms a few times to ensure parent-inherited values are caluclated correctly, and to ensure // we dont end up with some values read during a ffxiv frame update. for (int i = 0; i < 3; i++) { foreach ((string name, Bone? savedBone) in this.Bones) { if (savedBone == null) { continue; } BoneVisual3d?bone = skeleton.GetBone(name); if (bone == null) { Log.Warning($"Bone: \"{name}\" not found"); continue; } if (selectionOnly && !skeleton.GetIsBoneSelected(bone)) { continue; } TransformPtrViewModel vm = bone.ViewModel; if (PoseService.Instance.FreezePositions && savedBone.Position != null && config.LoadPositions) { vm.Position = (Vector)savedBone.Position; } if (PoseService.Instance.FreezeRotation && savedBone.Rotation != null && config.LoadRotations) { vm.Rotation = (Quaternion)savedBone.Rotation; } if (PoseService.Instance.FreezeScale && savedBone.Scale != null && config.LoadScales) { vm.Scale = (Vector)savedBone.Scale; } bone.ReadTransform(); bone.WriteTransform(skeleton, false); } await Task.Delay(1); } } // Restore the head bone rotation if we were only loading an expression if (headBone != null && originalHeadRotation != null) { headBone.ViewModel.Rotation = (Quaternion)originalHeadRotation; headBone.ReadTransform(); headBone.WriteTransform(skeleton, true); } await Task.Delay(100); skeletonMem.MemoryMode = MemoryModes.ReadWrite; await skeletonMem.ReadFromMemoryAsync(); PoseService.Instance.CanEdit = true; }
private void OnUnloaded(object sender, RoutedEventArgs e) { SkeletonViewModel vm = this.DataContext as SkeletonViewModel; this.Viewport.Children.Remove(vm.Root); }
private void GenerateBones() { this.Bones = new List <BoneVisual3d>(); // only show actors that have a body if (this.Actor?.ModelObject?.Skeleton?.Skeleton == null) { return; } SkeletonViewModel skeletonVm = this.Actor.ModelObject.Skeleton.Skeleton; if (skeletonVm.Body == null) { return; } // Body bones List <BoneVisual3d> bodyBones = new List <BoneVisual3d>(); for (int i = 0; i < skeletonVm.Body.Count; i++) { BoneVisual3d bone = new BoneVisual3d(skeletonVm.Body.Transforms[i], this); bodyBones.Add(bone); this.Bones.Add(bone); ////this.RootBones.Add(bone); } for (int i = 0; i < skeletonVm.Body.Count; i++) { int parent = SkeletonUtility.PlayerBodyParents[i]; if (parent == -1 || parent > bodyBones.Count) { this.Children.Add(bodyBones[i]); } else { bodyBones[i].Parent = bodyBones[parent]; } } int headBoneIndex = SkeletonUtility.BodyBoneIndexLookup["Head"]; BoneVisual3d?headRoot = null; if (headBoneIndex < bodyBones.Count) { headRoot = bodyBones[headBoneIndex]; } if (skeletonVm.Head != null) { foreach (TransformViewModel boneTrans in skeletonVm.Head.Transforms) { BoneVisual3d bone = new BoneVisual3d(boneTrans, this); this.Bones.Add(bone); bone.Parent = headRoot; if (headRoot == null) { this.Children.Add(bone); } } } if (skeletonVm.Hair != null) { foreach (TransformViewModel boneTrans in skeletonVm.Hair.Transforms) { BoneVisual3d bone = new BoneVisual3d(boneTrans, this); this.Bones.Add(bone); bone.Parent = headRoot; if (headRoot == null) { this.Children.Add(bone); } } } if (skeletonVm.Met != null) { foreach (TransformViewModel boneTrans in skeletonVm.Met.Transforms) { BoneVisual3d bone = new BoneVisual3d(boneTrans, this); this.Bones.Add(bone); this.Children.Add(bone); } } if (skeletonVm.Top != null) { foreach (TransformViewModel boneTrans in skeletonVm.Top.Transforms) { BoneVisual3d bone = new BoneVisual3d(boneTrans, this); this.Bones.Add(bone); this.Children.Add(bone); } } foreach (BoneVisual3d bone in this.Bones) { bone.ReadTransform(); } foreach (BoneVisual3d bone in this.Bones) { bone.ReadTransform(); } }
public SkeletonView() { InitializeComponent(); DataContext = SkeletonViewModel; SkeletonViewModel.Initialize(frame, NavView, KeyboardAccelerators); }