Skip to content

Commit

Permalink
Merge pull request #1424 from imchillin/testing
Browse files Browse the repository at this point in the history
Merge Testing into Main
  • Loading branch information
StoiaCode authored Jan 1, 2025
2 parents bdb2f5f + 2b54431 commit 86e9a9a
Show file tree
Hide file tree
Showing 37 changed files with 2,540 additions and 1,418 deletions.
25 changes: 22 additions & 3 deletions Anamnesis/Actor/Pages/CharacterPage.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -130,13 +130,32 @@
</Grid>
</GroupBox>

<!-- Warning for making sure the actor can be edited. (Out of GPOSE when not using Brio or Penumbra integrations) -->
<!-- Warning messages indicating that the actor's appearance cannot be edited. -->
<XivToolsWpf:InfoControl
Key="Character_WarningGposeWorldPosFrozen"
Grid.Column="0"
Grid.ColumnSpan="2"
Margin="12">
<XivToolsWpf:InfoControl.Visibility>
<MultiBinding Converter="{StaticResource MultiBoolAndToVisibility}">
<Binding Path="Actor.CanRefresh" Converter="{StaticResource !B}"/>
<Binding Path="PoseService.FreezeWorldPosition"/>
</MultiBinding>
</XivToolsWpf:InfoControl.Visibility>
</XivToolsWpf:InfoControl>

<XivToolsWpf:InfoControl
Key="Character_WarningGpose"
Grid.Column="0"
Grid.ColumnSpan="2"
Margin="12"
Visibility="{Binding Actor.CanRefresh, Converter={StaticResource !B2V}}" />
Margin="12">
<XivToolsWpf:InfoControl.Visibility>
<MultiBinding Converter="{StaticResource MultiBoolAndToVisibility}">
<Binding Path="Actor.CanRefresh" Converter="{StaticResource !B}"/>
<Binding Path="PoseService.WorldPositionNotFrozen"/>
</MultiBinding>
</XivToolsWpf:InfoControl.Visibility>
</XivToolsWpf:InfoControl>

<!-- Other Actor Settings - Incl Subactor (Mount/Minion/FashAcc), Facewear, Extended Appearance -->
<Grid Grid.Column="2">
Expand Down
1 change: 1 addition & 0 deletions Anamnesis/Actor/Pages/CharacterPage.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ public CharacterPage()

public ActorMemory? Actor { get; private set; }
public ListCollectionView VoiceEntries { get; private set; }
public PoseService PoseService => PoseService.Instance;

private void OnLoaded(object sender, RoutedEventArgs e)
{
Expand Down
9 changes: 9 additions & 0 deletions Anamnesis/Actor/Pages/PosePage.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,15 @@
</MenuItem.ToolTip>
</MenuItem>

<!-- (Import) Weapons Only -->
<MenuItem Header="Pose_WeaponsOnly"
Style="{StaticResource AnaMenuItem}"
Click="OnImportWeaponsClicked">
<MenuItem.ToolTip>
<XivToolsWpf:TextBlock Key="Pose_WeaponsOnlyTooltip" />
</MenuItem.ToolTip>
</MenuItem>

<!-- (Import) Selected Bones -->
<MenuItem Header="Pose_Selected"
Style="{StaticResource AnaMenuItem}"
Expand Down
39 changes: 31 additions & 8 deletions Anamnesis/Actor/Pages/PosePage.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ private enum PoseImportOptions
BodyOnly, // Imports only the body part of the pose.
ExpressionOnly, // Imports only the facial expression part of the pose.
SelectedBones, // Imports only the selected bones.
WeaponsOnly, // Imports only the weapons (main hand and off-hand).
}

public SettingsService SettingsService => SettingsService.Instance;
Expand Down Expand Up @@ -295,11 +296,13 @@ private async void OnDataContextChanged(object? sender, DependencyPropertyChange

if (this.Actor?.ModelObject != null)
{
this.Actor.Refreshed -= this.OnActorRefreshed;
this.Actor.ModelObject.PropertyChanged -= this.OnModelObjectChanged;
}

if (newActor?.ModelObject != null)
{
newActor.Refreshed += this.OnActorRefreshed;
newActor.ModelObject.PropertyChanged += this.OnModelObjectChanged;
}

Expand All @@ -308,13 +311,18 @@ private async void OnDataContextChanged(object? sender, DependencyPropertyChange
await this.Refresh();
}

private void OnActorRefreshed(object? sender, EventArgs? e)
{
// Restart the debounce timer if it's already running, otherwise start it.
this.refreshDebounceTimer.Stop();
this.refreshDebounceTimer.Start();
}

private void OnModelObjectChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(ActorModelMemory.Skeleton))
{
// Restart the debounce timer if it's already running, otherwise start it.
this.refreshDebounceTimer.Stop();
this.refreshDebounceTimer.Start();
this.OnActorRefreshed(null, default);
}
}

Expand All @@ -338,10 +346,9 @@ private async Task Refresh()

try
{
if (this.Skeleton == null)
this.Skeleton = new SkeletonVisual3d();

await this.Skeleton.SetActor(this.Actor);
SkeletonVisual3d newSkeleton = this.Skeleton ?? new SkeletonVisual3d();
await newSkeleton.SetActor(this.Actor);
this.Skeleton = newSkeleton;

this.ThreeDView.DataContext = this.Skeleton;
this.BodyGuiView.DataContext = this.Skeleton;
Expand All @@ -361,7 +368,9 @@ private async Task Refresh()

private async void OnImportClicked(object sender, RoutedEventArgs e)
{
await this.ImportPose(PoseImportOptions.Character, PoseFile.Mode.All);
bool isShiftPressed = Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift);
PoseFile.Mode mode = isShiftPressed ? PoseFile.Mode.All : (PoseFile.Mode.All & ~PoseFile.Mode.Scale);
await this.ImportPose(PoseImportOptions.Character, mode);
this.Skeleton?.ClearSelection();
}

Expand All @@ -385,6 +394,11 @@ private async void OnImportSelectedBonesClicked(object sender, RoutedEventArgs e
await this.HandleSecondaryOptionImport(PoseImportOptions.SelectedBones);
}

private async void OnImportWeaponsClicked(object sender, RoutedEventArgs e)
{
await this.HandleSecondaryOptionImport(PoseImportOptions.WeaponsOnly);
}

private async Task ImportPose(PoseImportOptions importOption, PoseFile.Mode mode)
{
if (this.Actor == null || this.Skeleton == null)
Expand Down Expand Up @@ -453,6 +467,15 @@ private async Task ImportPose(PoseImportOptions importOption, PoseFile.Mode mode
return;
}

if (importOption == PoseImportOptions.WeaponsOnly)
{
this.Skeleton.SelectWeapons();
var selectedBoneNames = this.Skeleton.SelectedBones.Select(bone => bone.BoneName).ToHashSet();
poseFile.Apply(this.Actor, this.Skeleton, selectedBoneNames, mode, false);
this.Skeleton.ClearSelection();
return;
}

// Backup face bone positions before importing the body pose.
// "Freeze Position" toggle resets them, so restore after import. Relevant only when pose service is enabled.
this.Skeleton.SelectHead();
Expand Down
2 changes: 1 addition & 1 deletion Anamnesis/Actor/Posing/Services/PoseService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ public void SetEnabled(bool enabled)
this.FreezePhysics = enabled;
this.FreezeRotation = enabled;
this.FreezePositions = enabled;
this.FreezeScale = enabled;
this.FreezeScale = false;
this.EnableParenting = true;

/*if (enabled)
Expand Down
2 changes: 1 addition & 1 deletion Anamnesis/Actor/Posing/Views/Pose3DView.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
<StackPanel
IsEnabled="True"
Orientation="Horizontal"
Margin="100, 0, 0, 0"
Margin="130, 0, 0, 0"
VerticalAlignment="Top">

<Button Padding="6,2"
Expand Down
Loading

0 comments on commit 86e9a9a

Please sign in to comment.