Skip to content

Commit

Permalink
Merge pull request #1010 from AsgardXIV/newcam
Browse files Browse the repository at this point in the history
Camera Shot System
  • Loading branch information
Yuki-Codes authored Apr 21, 2022
2 parents 47a5bb3 + 48b1fb8 commit 2905992
Show file tree
Hide file tree
Showing 10 changed files with 200 additions and 3 deletions.
78 changes: 78 additions & 0 deletions Anamnesis/Files/CameraShotFile.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// © Anamnesis.
// Licensed under the MIT license.

namespace Anamnesis.Files
{
using System;
using Anamnesis.Memory;
using Anamnesis.PoseModule;

[Serializable]
public class CameraShotFile : JsonFileBase
{
public override string FileExtension => ".shot";
public override string TypeName => "Anamnesis Camera Shot";

public bool DelimitCamera { get; set; }
public float Zoom { get; set; }
public float FieldOfView { get; set; }
public Vector2D Pan { get; set; }
public Vector Position { get; set; }
public Vector Rotation { get; set; }

public void Apply(CameraService camService, ActorMemory actor)
{
camService.DelimitCamera = this.DelimitCamera;
camService.Camera.Zoom = this.Zoom;
camService.Camera.FieldOfView = this.FieldOfView;
camService.Camera.Pan = this.Pan;

if (actor.ModelObject?.Transform?.Rotation != null && actor.ModelObject?.Transform?.Position != null)
{
// We assume the actor is stood flat on the ground
Vector actorEuler = actor.ModelObject.Transform.Rotation.ToEuler();
actorEuler.X = 0;
actorEuler.Z = 0;

// First we use the 0 rotation position and rotate it around the actor by it's current rotation in local space
Vector rotatedRelativePosition = Quaternion.FromEuler(actorEuler) * this.Position;

// Adjust camera position to world space
camService.GPoseCamera.Position = actor.ModelObject.Transform.Position + rotatedRelativePosition;

// Now we apply the angle offset of the camera to the actor
Vector adjusted = actorEuler + this.Rotation;
camService.Camera.Euler = adjusted.ToMedia3DVector();
}
}

public void WriteToFile(CameraService camService, ActorMemory actor)
{
this.DelimitCamera = camService.DelimitCamera;
this.Zoom = camService.Camera.Zoom;
this.FieldOfView = camService.Camera.FieldOfView;
this.Pan = camService.Camera.Pan;

if (actor.ModelObject?.Transform?.Rotation != null && actor.ModelObject?.Transform?.Position != null)
{
// We assume the actor is stood flat on the ground
Vector actorEuler = actor.ModelObject.Transform.Rotation.ToEuler();
actorEuler.Z = 0;
actorEuler.X = 0;

// First we get the local coords of the current camera position in relation to the actor
Vector localRelativePositon = camService.GPoseCamera.Position - actor.ModelObject.Transform.Position;

// Now we calculate what the position would be if the actor had a 0 rotation
Quaternion invertedActorRotation = Quaternion.FromEuler(actorEuler);
invertedActorRotation.Invert();
Vector rotatedRelativePosition = invertedActorRotation * localRelativePositon;
this.Position = rotatedRelativePosition;

// We save the angle of the camera as an offset from the angle of the actor
Vector cameraEuler = camService.Camera.Euler.ToCmVector();
this.Rotation = cameraEuler - actorEuler;
}
}
}
}
5 changes: 5 additions & 0 deletions Anamnesis/Files/FileService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ public class FileService : ServiceBase<FileService>
"Shortcuts/Anamnesis.png",
"Shortcut_AnamnesisCharacter");

public static Shortcut DefaultCameraDirectory => new Shortcut(
new DirectoryInfo(ParseToFilePath(SettingsService.Current.DefaultCameraShotDirectory)),
"Shortcuts/Anamnesis.png",
"Shortcut_AnamnesisScenes");

public static Shortcut DefaultSceneDirectory => new Shortcut(
new DirectoryInfo(ParseToFilePath(SettingsService.Current.DefaultSceneDirectory)),
"Shortcuts/Anamnesis.png",
Expand Down
1 change: 1 addition & 0 deletions Anamnesis/Languages/cn.json
Original file line number Diff line number Diff line change
Expand Up @@ -561,6 +561,7 @@
"Settings_Directories": "文件夹位置",
"Settings_Dir_Characters": "角色",
"Settings_Dir_Poses": "动作造型",
"Settings_Dir_CameraShots": "相机拍摄",
"Settings_Dir_Scenes": "场景",
"Settings_GalleryHeader": "画廊",
"Settings_Gallery": "模式",
Expand Down
1 change: 1 addition & 0 deletions Anamnesis/Languages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -566,6 +566,7 @@
"Settings_Directories": "Directories",
"Settings_Dir_Characters": "Characters",
"Settings_Dir_Poses": "Poses",
"Settings_Dir_CameraShots": "Cam Shots",
"Settings_Dir_Scenes": "Scenes",
"Settings_GalleryHeader": "Gallery",
"Settings_Gallery": "Mode",
Expand Down
21 changes: 21 additions & 0 deletions Anamnesis/Memory/CameraMemory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,27 @@ public System.Windows.Media.Media3D.Quaternion Rotation3d
}
}

[AlsoNotifyFor(nameof(CameraMemory.Angle), nameof(CameraMemory.Rotation))]
public Vector3D Euler
{
get
{
Vector3D camEuler = default;
camEuler.Y = (float)MathUtils.RadiansToDegrees((double)this.Angle.X);
camEuler.Z = (float)MathUtils.RadiansToDegrees((double)this.Angle.Y);
camEuler.X = (float)MathUtils.RadiansToDegrees((double)this.Rotation);
return camEuler;
}

set
{
this.Rotation = (float)MathUtils.DegreesToRadians(value.X);
var angleX = (float)MathUtils.DegreesToRadians(value.Y);
var angleY = (float)MathUtils.DegreesToRadians(value.Z);
this.Angle = new Vector2D(angleX, angleY);
}
}

public bool FreezeAngle
{
get => this.IsFrozen(nameof(CameraMemory.Angle));
Expand Down
1 change: 1 addition & 0 deletions Anamnesis/Services/Settings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ public enum Fonts
public Point OverlayWindowPosition { get; set; }
public string DefaultPoseDirectory { get; set; } = "%MyDocuments%/Anamnesis/Poses/";
public string DefaultCharacterDirectory { get; set; } = "%MyDocuments%/Anamnesis/Characters/";
public string DefaultCameraShotDirectory { get; set; } = "%MyDocuments%/Anamnesis/CameraShots/";
public string DefaultSceneDirectory { get; set; } = "%MyDocuments%/Anamnesis/Scenes/";
public bool ShowAdvancedOptions { get; set; } = true;
public bool FlipPoseGuiSides { get; set; } = false;
Expand Down
10 changes: 8 additions & 2 deletions Anamnesis/Views/SceneView.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -297,8 +297,9 @@
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>

<XivToolsWpf:TextBlock Grid.Row="0"
Key="Scene_Camera_Delimit"
Expand Down Expand Up @@ -413,6 +414,11 @@
Maximum="100"
TickFrequency="1" />

<Menu Grid.Row="8" Grid.Column="0" Grid.ColumnSpan="2" Style="{StaticResource AnaMenu}" HorizontalAlignment="Right" VerticalAlignment="Bottom">
<MenuItem Header="Common_OpenFile" Icon="FolderOpen" Click="OnLoadCamera" Style="{StaticResource ButtonMenuItem}" Margin="1" MinWidth="75"/>
<MenuItem Header="Common_SaveFile" Icon="Save" Click="OnSaveCamera" Style="{StaticResource ButtonMenuItem}" Margin="1" MinWidth="75"/>
</Menu>


<XivToolsWpf:InfoControl Grid.RowSpan="10"
Grid.ColumnSpan="2"
Expand Down
67 changes: 67 additions & 0 deletions Anamnesis/Views/SceneView.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@

namespace Anamnesis.Views
{
using System;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using Anamnesis.Files;
using Anamnesis.Memory;
using Anamnesis.Services;
using Anamnesis.Styles.Drawers;
using PropertyChanged;
Expand All @@ -16,6 +20,9 @@ namespace Anamnesis.Views
[AddINotifyPropertyChangedInterface]
public partial class SceneView : UserControl
{
private static DirectoryInfo? lastLoadDir;
private static DirectoryInfo? lastSaveDir;

public SceneView()
{
this.InitializeComponent();
Expand Down Expand Up @@ -47,5 +54,65 @@ private void OnWeatherClicked(object sender, RoutedEventArgs e)
this.TerritoryService.CurrentWeather = w;
});
}

private async void OnLoadCamera(object sender, RoutedEventArgs e)
{
ActorBasicMemory? targetActor = this.TargetService.PlayerTarget;
if (targetActor == null || !targetActor.IsValid)
return;
ActorMemory actorMemory = new ActorMemory();
actorMemory.SetAddress(targetActor.Address);

try
{
Shortcut[]? shortcuts = new[]
{
FileService.DefaultCameraDirectory,
};

Type[] types = new[]
{
typeof(CameraShotFile),
};

OpenResult result = await FileService.Open(lastLoadDir, shortcuts, types);

if (result.File == null)
return;

lastLoadDir = result.Directory;

if (result.File is CameraShotFile camFile)
{
camFile.Apply(CameraService.Instance, actorMemory);
}
}
catch (Exception ex)
{
Log.Error(ex, "Failed to load camera");
}
}

private async void OnSaveCamera(object sender, RoutedEventArgs e)
{
ActorBasicMemory? targetActor = this.TargetService.PlayerTarget;
if (targetActor == null || !targetActor.IsValid)
return;
ActorMemory actorMemory = new ActorMemory();
actorMemory.SetAddress(targetActor.Address);

SaveResult result = await FileService.Save<CameraShotFile>(lastSaveDir, FileService.DefaultCameraDirectory);

if (result.Path == null)
return;

lastSaveDir = result.Directory;

CameraShotFile file = new CameraShotFile();
file.WriteToFile(CameraService.Instance, actorMemory);

using FileStream stream = new FileStream(result.Path.FullName, FileMode.Create);
file.Serialize(stream);
}
}
}
7 changes: 6 additions & 1 deletion Anamnesis/Views/SettingsView.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>

<XivToolsWPF:TextBlock Grid.Row="0" Grid.Column="0" Key="Settings_Dir_Characters" Style="{StaticResource Label}"/>
Expand All @@ -216,7 +217,11 @@

<XivToolsWPF:TextBlock Grid.Row="1" Grid.Column="0" Key="Settings_Dir_Poses" Style="{StaticResource Label}"/>
<TextBox Grid.Row="1" Grid.Column="1" Margin="3, 0, 0, 0" Style="{StaticResource MaterialDesignTextBox}" Text="{Binding SettingsService.Settings.DefaultPoseDirectory}" IsEnabled="False"/>
<Button Grid.Row="1" Grid.Column="2" Margin="6, 3, 0, 0" Style="{StaticResource TransparentButton}" Content="..." Click="OnBrowsePose"/>
<Button Grid.Row="1" Grid.Column="2" Margin="6, 3, 0, 0" Style="{StaticResource TransparentButton}" Content="..." Click="OnBrowsePose"/>

<XivToolsWPF:TextBlock Grid.Row="2" Grid.Column="0" Key="Settings_Dir_CameraShots" Style="{StaticResource Label}"/>
<TextBox Grid.Row="2" Grid.Column="1" Margin="3, 0, 0, 0" Style="{StaticResource MaterialDesignTextBox}" Text="{Binding SettingsService.Settings.DefaultCameraShotDirectory}" IsEnabled="False"/>
<Button Grid.Row="2" Grid.Column="2" Margin="6, 3, 0, 0" Style="{StaticResource TransparentButton}" Content="..." Click="OnBrowseCamera"/>

<!--
<ana:TextBlock Grid.Row="2" Grid.Column="0" Key="Settings_Dir_Scenes" Style="{StaticResource Label}"/>
Expand Down
12 changes: 12 additions & 0 deletions Anamnesis/Views/SettingsView.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,18 @@ private void OnBrowsePose(object sender, RoutedEventArgs e)
SettingsService.Current.DefaultPoseDirectory = FileService.ParseFromFilePath(dlg.SelectedPath);
}

private void OnBrowseCamera(object sender, RoutedEventArgs e)
{
FolderBrowserDialog dlg = new FolderBrowserDialog();
dlg.SelectedPath = FileService.ParseToFilePath(SettingsService.Current.DefaultCameraShotDirectory);
DialogResult result = dlg.ShowDialog();

if (result != DialogResult.OK)
return;

SettingsService.Current.DefaultCameraShotDirectory = FileService.ParseFromFilePath(dlg.SelectedPath);
}

private void OnBrowseScene(object sender, RoutedEventArgs e)
{
FolderBrowserDialog dlg = new FolderBrowserDialog();
Expand Down

0 comments on commit 2905992

Please sign in to comment.