mirror of
https://github.com/4sval/FModel.git
synced 2026-03-27 12:15:09 -05:00
socket frontend
This commit is contained in:
parent
bf171b28cd
commit
8d986c4dc6
|
|
@ -1 +1 @@
|
|||
Subproject commit 581d29b275a2581c2b246991fe8e5f988605e0b5
|
||||
Subproject commit ae298a23de24f0b05e101a0fc8f0192667f0ed4b
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
BIN
FModel/Resources/link_off.png
Normal file
BIN
FModel/Resources/link_off.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 311 B |
BIN
FModel/Resources/link_on.png
Normal file
BIN
FModel/Resources/link_on.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 235 B |
|
|
@ -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];
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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 =>
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user