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; }
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; }