public void WriteToFile(ActorViewModel actor, SkeletonVisual3d skeleton, Configuration config) { this.Config = config; ////SkeletonViewModel? skeletonMem = actor?.ModelObject?.Skeleton?.Skeleton; if (skeleton == null || skeleton.Bones == null) { throw new Exception("No skeleton in actor"); } this.Bones = new Dictionary <string, Bone?>(); foreach (BoneVisual3d bone in skeleton.Bones) { if (config.UseSelection && !skeleton.GetIsBoneSelected(bone)) { continue; } Transform?trans = bone.ViewModel.Model; if (trans == null) { throw new Exception("Bone is missing transform"); } this.Bones.Add(bone.BoneName, new Bone(trans.Value)); } }
public void FromActor(ActorViewModel actor, SkeletonVisual3d skeleton, Vector rootPos, Configuration config) { if (actor.ModelObject?.Transform != null) { if (config.IncludeActorPosition) { this.Position = rootPos - actor.ModelObject.Transform.Position; } if (config.IncludeActorRotation) { this.Rotation = actor.ModelObject.Transform.Rotation; } if (config.IncludeActorScale) { this.Scale = actor.ModelObject.Transform.Scale; } } this.Pose = new PoseFile(); this.Pose.WriteToFile(actor, skeleton, config.Pose); this.Character = new CharacterFile(); this.Character.WriteToFile(actor, config.Character); }
public static async Task ParentBones(SkeletonVisual3d root, IEnumerable <BoneVisual3d> bones) { PoseService.Instance.IsEnabled = true; PoseService.Instance.EnableParenting = false; try { foreach (BoneVisual3d bone in bones) { root.Children.Add(bone); bone.ReadTransform(); } foreach (BoneVisual3d bone in bones) { await ParentBone(root, bones, bone); } } catch (Exception) { throw; } finally { PoseService.Instance.IsEnabled = false; } }
private async void ExportPose(TargetService.ActorTableActor actor) { ActorViewModel?actorVm = actor.GetViewModel(); if (actorVm == null) { return; } SkeletonVisual3d skeletonVm = await PoseService.GetVisual(actorVm); await PoseFile.Save(actorVm, skeletonVm); }
private void OnGroupClicked(object sender, System.Windows.RoutedEventArgs e) { if (sender is DependencyObject ob) { GroupBox?groupBox = ob.FindParent <GroupBox>(); if (groupBox == null) { return; } SkeletonVisual3d skeleton = (SkeletonVisual3d)this.DataContext; if (!Keyboard.IsKeyDown(Key.LeftCtrl)) { skeleton.SelectedBones.Clear(); } List <BoneView> bones = groupBox.FindChildren <BoneView>(); skeleton.Select(bones); } }
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 static async Task ParentBone(SkeletonVisual3d root, IEnumerable <BoneVisual3d> bones, BoneVisual3d bone) { // Must wait for ffxiv to update at least one frame await Task.Delay(75); await Dispatch.MainThread(); // Get the positions of all bones Dictionary <BoneVisual3d, Vector> initialBonePositions = new Dictionary <BoneVisual3d, Vector>(); foreach (BoneVisual3d otherBone in bones) { otherBone.ReadTransform(); initialBonePositions.Add(otherBone, otherBone.Position); } // rotate the test bone Quaternion oldRot = bone.Rotation; bone.Rotation *= Quaternion.FromEuler(new Vector(0, 90, 0)); bone.WriteTransform(root, false); bone.ViewModel.WriteToMemory(true); // Must wait for ffxiv to update at least one frame await Task.Delay(75); await Dispatch.MainThread(); // See if any bones moved as a result of the test bone rotation foreach (BoneVisual3d otherBone in bones) { if (otherBone == bone) { continue; } otherBone.ReadTransform(); // If this bone has moved, then it is a child of the test bone. if (initialBonePositions[otherBone] != otherBone.Position) { //// If this bone is already a child of the testbones hierarchy, dont move it. if (IsChildOf(otherBone, bone)) { continue; } if (IsChildOf(bone, otherBone)) { Log.Warning("Bone that is parent of test bone was moved."); continue; ////throw new Exception("Bone that is parent of test bone was moved."); } otherBone.Parent = bone; } } // Restore the test bone rotation bone.Rotation = oldRot; bone.WriteTransform(root, false); bone.ViewModel.WriteToMemory(true); // restore all initial bone positions foreach (BoneVisual3d otherBone in bones) { otherBone.ReadTransform(); if (initialBonePositions[otherBone] != otherBone.Position) { otherBone.Position = initialBonePositions[otherBone]; otherBone.WriteTransform(root, false); } } }
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; }