socket frontend

This commit is contained in:
4sval 2023-01-09 19:06:50 +01:00
parent bf171b28cd
commit 8d986c4dc6
9 changed files with 60 additions and 48 deletions

@ -1 +1 @@
Subproject commit 581d29b275a2581c2b246991fe8e5f988605e0b5
Subproject commit ae298a23de24f0b05e101a0fc8f0192667f0ed4b

View File

@ -227,6 +227,8 @@
<Resource Include="Resources\pz.png" />
<Resource Include="Resources\pointlight.png" />
<Resource Include="Resources\spotlight.png" />
<Resource Include="Resources\link_on.png" />
<Resource Include="Resources\link_off.png" />
</ItemGroup>
<ItemGroup>

Binary file not shown.

After

Width:  |  Height:  |  Size: 311 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 235 B

View File

@ -54,6 +54,8 @@ public class Model : IDisposable
public bool HasSockets => Sockets.Length > 0;
public readonly Socket[] Sockets;
public bool IsAttached { get; private set; }
public string AttachedTo { get; private set; }
public int TransformsCount;
public readonly List<Transform> Transforms;
@ -63,7 +65,7 @@ public class Model : IDisposable
public bool Show;
public bool Wireframe;
public bool IsSetup;
public bool IsSetup { get; private set; }
public bool IsSelected;
public int SelectedInstance;
public float MorphTime;
@ -88,7 +90,7 @@ public class Model : IDisposable
for (int i = 0; i < Sockets.Length; i++)
{
if (export.Sockets[i].Load<UStaticMeshSocket>() is not { } socket) continue;
Sockets[i] = new Socket(socket);
Sockets[i] = new Socket(socket, Transforms[0]);
}
}
private Model(USkeletalMesh export, CSkeletalMesh skeletalMesh, Transform transform) : this(export, export.Materials, export.Skeleton, skeletalMesh.LODs.Count, skeletalMesh.LODs[0], skeletalMesh.LODs[0].Verts, transform)
@ -106,13 +108,9 @@ public class Model : IDisposable
if (!Skeleton.BonesIndexByName.TryGetValue(socket.BoneName.Text, out var boneIndex) ||
!Skeleton.BonesTransformByIndex.TryGetValue(boneIndex, out var boneTransform))
{
Sockets[i] = new Socket(socket);
}
else
{
Sockets[i] = new Socket(socket, boneTransform);
}
boneTransform = Transforms[0];
Sockets[i] = new Socket(socket, boneTransform);
}
}
public Model(USkeletalMesh export, CSkeletalMesh skeletalMesh) : this(export, skeletalMesh, Transform.Identity)
@ -217,6 +215,7 @@ public class Model : IDisposable
if (section.IsValid) Sections[s].SetupMaterial(Materials[section.MaterialIndex]);
}
_previousMatrix = t.Matrix;
AddInstance(t);
}
@ -224,13 +223,12 @@ public class Model : IDisposable
{
TransformsCount++;
Transforms.Add(transform);
_previousMatrix = transform.Matrix;
}
public void UpdateMatrices(Options options)
{
UpdateMatrices();
if (!HasSkeleton)
if (!HasSockets)
return;
for (int s = 0; s < Sockets.Length; s++)
@ -271,6 +269,23 @@ public class Model : IDisposable
_morphVbo.Unbind();
}
public void AttachModel(Model attachedTo, Socket socket)
{
IsAttached = true;
AttachedTo = $"'{socket.Name}' from '{attachedTo.Name}'{(socket.Bone.HasValue ? $" at '{socket.Bone}'" : "")}";
// reset PRS to 0 so it's attached to the actual position (can be transformed relative to the socket later by the user)
Transforms[SelectedInstance].Position = FVector.ZeroVector;
Transforms[SelectedInstance].Rotation = FQuat.Identity;
Transforms[SelectedInstance].Scale = FVector.OneVector;
}
public void DetachModel()
{
IsAttached = false;
AttachedTo = null;
Transforms[SelectedInstance].Relation = _previousMatrix;
}
public void SetupInstances()
{
var instanceMatrix = new Matrix4x4[TransformsCount];

View File

@ -4,36 +4,28 @@ using System.Numerics;
using CUE4Parse.UE4.Assets.Exports.SkeletalMesh;
using CUE4Parse.UE4.Assets.Exports.StaticMesh;
using CUE4Parse.UE4.Objects.Core.Misc;
using CUE4Parse.UE4.Objects.UObject;
namespace FModel.Views.Snooper.Models;
public class Socket : IDisposable
{
public readonly string Name;
public readonly string Bone;
public readonly FName? Bone;
public readonly Transform Transform;
public readonly List<FGuid> AttachedModels;
private Socket()
{
Bone = "None";
Transform = Transform.Identity;
AttachedModels = new List<FGuid>();
}
public Socket(UStaticMeshSocket socket) : this()
public Socket(UStaticMeshSocket socket, Transform transform) : this()
{
Name = socket.SocketName.Text;
Transform.Rotation = socket.RelativeRotation.Quaternion();
Transform.Position = socket.RelativeLocation * Constants.SCALE_DOWN_RATIO;
Transform.Scale = socket.RelativeScale;
}
public Socket(USkeletalMeshSocket socket) : this()
{
Name = socket.SocketName.Text;
Bone = socket.BoneName.Text;
Transform.Relation = transform.Matrix;
Transform.Rotation = socket.RelativeRotation.Quaternion();
Transform.Position = socket.RelativeLocation * Constants.SCALE_DOWN_RATIO;
Transform.Scale = socket.RelativeScale;
@ -42,7 +34,7 @@ public class Socket : IDisposable
public Socket(USkeletalMeshSocket socket, Transform transform) : this()
{
Name = socket.SocketName.Text;
Bone = socket.BoneName.Text;
Bone = socket.BoneName;
Transform.Relation = transform.Matrix;
Transform.Rotation = socket.RelativeRotation.Quaternion();
Transform.Position = socket.RelativeLocation * Constants.SCALE_DOWN_RATIO;

View File

@ -36,6 +36,8 @@ public class Options
["noimage"] = new ("T_Placeholder_Item_Image"),
["pointlight"] = new ("pointlight"),
["spotlight"] = new ("spotlight"),
["link_on"] = new ("link_on"),
["link_off"] = new ("link_off"),
};
_platform = UserSettings.Default.OverridedPlatform;

View File

@ -7,7 +7,6 @@ using ImGuiNET;
using OpenTK.Windowing.Common;
using System.Numerics;
using System.Text;
using CUE4Parse.UE4.Objects.Core.Math;
using FModel.Settings;
using FModel.Views.Snooper.Models;
using FModel.Views.Snooper.Shading;
@ -56,6 +55,7 @@ public class SnimGui
private readonly Vector4 _errorColor = new (0.761f, 0.169f, 0.169f, 1.0f);
private const uint _dockspaceId = 1337;
private const float _tableWidth = 17;
public SnimGui(int width, int height)
{
@ -300,11 +300,12 @@ Snooper aims to give an accurate preview of models, materials, skeletal animatio
ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, Vector2.Zero);
Window("Outliner", () =>
{
if (ImGui.BeginTable("Items", 3, ImGuiTableFlags.Resizable | ImGuiTableFlags.BordersOuterV, ImGui.GetContentRegionAvail()))
if (ImGui.BeginTable("Items", 4, ImGuiTableFlags.Resizable | ImGuiTableFlags.BordersOuterV | ImGuiTableFlags.NoSavedSettings, ImGui.GetContentRegionAvail()))
{
ImGui.TableSetupColumn("Instance", ImGuiTableColumnFlags.NoHeaderWidth | ImGuiTableColumnFlags.WidthFixed);
ImGui.TableSetupColumn("Channels", ImGuiTableColumnFlags.WidthFixed);
ImGui.TableSetupColumn("Name");
ImGui.TableSetupColumn("Instance", ImGuiTableColumnFlags.NoHeaderWidth | ImGuiTableColumnFlags.WidthFixed, _tableWidth);
ImGui.TableSetupColumn("Channels", ImGuiTableColumnFlags.NoHeaderWidth | ImGuiTableColumnFlags.WidthFixed, _tableWidth);
ImGui.TableSetupColumn("Name", ImGuiTableColumnFlags.WidthStretch);
ImGui.TableSetupColumn("", ImGuiTableColumnFlags.NoHeaderWidth | ImGuiTableColumnFlags.WidthFixed, _tableWidth);
ImGui.TableHeadersRow();
var i = 0;
@ -314,9 +315,9 @@ Snooper aims to give an accurate preview of models, materials, skeletal animatio
ImGui.TableNextRow();
ImGui.TableNextColumn();
if (!model.Show)
{
ImGui.TableSetBgColor(ImGuiTableBgTarget.RowBg0, ImGui.GetColorU32(new Vector4(1, 0, 0, .5f)));
}
if (model.IsAttached)
ImGui.TableSetBgColor(ImGuiTableBgTarget.RowBg0, ImGui.GetColorU32(new Vector4(1, 1, 0, .5f)));
ImGui.Text(model.TransformsCount.ToString("D"));
ImGui.TableNextColumn();
@ -326,7 +327,6 @@ Snooper aims to give an accurate preview of models, materials, skeletal animatio
{
s.Renderer.Options.SelectModel(guid);
}
Popup(() =>
{
s.Renderer.Options.SelectModel(guid);
@ -358,6 +358,11 @@ Snooper aims to give an accurate preview of models, materials, skeletal animatio
ImGui.Separator();
if (ImGui.Selectable("Copy Name to Clipboard")) ImGui.SetClipboardText(model.Name);
});
ImGui.TableNextColumn();
ImGui.Image(s.Renderer.Options.Icons[model.IsAttached ? "link_on" : "link_off"].GetPointer(), new Vector2(_tableWidth));
if (model.IsAttached) TooltipCopy($"Attached To {model.AttachedTo}");
ImGui.PopID();
i++;
}
@ -411,15 +416,11 @@ Snooper aims to give an accurate preview of models, materials, skeletal animatio
{
case false when ImGui.Button($"Attach to '{socket.Name}'"):
socket.AttachedModels.Add(selectedGuid);
// reset PRS to 0 so it's attached to the actual position (can be transformed relative to the socket later by the user)
selectedModel.Transforms[selectedModel.SelectedInstance].Position = FVector.ZeroVector;
selectedModel.Transforms[selectedModel.SelectedInstance].Rotation = FQuat.Identity;
selectedModel.Transforms[selectedModel.SelectedInstance].Scale = FVector.OneVector;
selectedModel.AttachModel(model, socket);
break;
case true when ImGui.Button($"Detach from '{socket.Name}'"):
socket.AttachedModels.Remove(selectedGuid);
// reset PRS relation to O
selectedModel.Transforms[selectedModel.SelectedInstance].Relation = Matrix4x4.Identity;
selectedModel.DetachModel();
break;
}
ImGui.PopID();
@ -451,26 +452,26 @@ Snooper aims to give an accurate preview of models, materials, skeletal animatio
{
if (ImGui.BeginTable("model_details", 2, ImGuiTableFlags.SizingStretchProp))
{
Layout("Entity");ImGui.Text($" : ({model.Type}) {model.Name}");
Layout("Guid");ImGui.Text($" : {s.Renderer.Options.SelectedModel.ToString(EGuidFormats.UniqueObjectGuid)}");
Layout("Entity");ImGui.Text($" : ({model.Type}) {model.Name}");
Layout("Guid");ImGui.Text($" : {s.Renderer.Options.SelectedModel.ToString(EGuidFormats.UniqueObjectGuid)}");
if (model.HasSkeleton)
{
Layout("Skeleton");ImGui.Text($" : {model.Skeleton.UnrealSkeleton.Name}");
Layout("Bones");ImGui.Text($" : x{model.Skeleton.UnrealSkeleton.BoneTree.Length}");
Layout("Skeleton");ImGui.Text($" : {model.Skeleton.UnrealSkeleton.Name}");
Layout("Bones");ImGui.Text($" : x{model.Skeleton.UnrealSkeleton.BoneTree.Length}");
}
else
{
Layout("Two Sided");ImGui.Text($" : {model.TwoSided}");
Layout("Two Sided");ImGui.Text($" : {model.TwoSided}");
}
Layout("Sockets");ImGui.Text($" : x{model.Sockets.Length}");
Layout("Sockets");ImGui.Text($" : x{model.Sockets.Length}");
ImGui.EndTable();
}
if (ImGui.BeginTabBar("tabbar_details", ImGuiTabBarFlags.None))
{
if (ImGui.BeginTabItem("Sections") && ImGui.BeginTable("table_sections", 2, ImGuiTableFlags.Resizable | ImGuiTableFlags.BordersOuterV, ImGui.GetContentRegionAvail()))
if (ImGui.BeginTabItem("Sections") && ImGui.BeginTable("table_sections", 2, ImGuiTableFlags.Resizable | ImGuiTableFlags.BordersOuterV | ImGuiTableFlags.NoSavedSettings, ImGui.GetContentRegionAvail()))
{
ImGui.TableSetupColumn("Index", ImGuiTableColumnFlags.WidthFixed);
ImGui.TableSetupColumn("Index", ImGuiTableColumnFlags.NoHeaderWidth | ImGuiTableColumnFlags.WidthFixed, _tableWidth);
ImGui.TableSetupColumn("Material");
ImGui.TableHeadersRow();

View File

@ -13,7 +13,7 @@ public class Transform
public Matrix4x4 Relation = Matrix4x4.Identity;
public FVector Position = FVector.ZeroVector;
public FQuat Rotation = new (0f);
public FQuat Rotation = FQuat.Identity;
public FVector Scale = FVector.OneVector;
public Matrix4x4 Matrix =>