mirror of
https://github.com/4sval/FModel.git
synced 2026-03-22 01:34:37 -05:00
removed guid from models + bone delta matrix + timeline scroller
This commit is contained in:
parent
0ed26e1a7d
commit
cdb52d096f
|
|
@ -15,10 +15,14 @@ public class Animation : IDisposable
|
|||
public readonly float StartTime; // Animation Start Time
|
||||
public readonly float EndTime; // Animation End Time
|
||||
public readonly float TotalElapsedTime; // Animation Max Time
|
||||
public readonly string TargetSkeleton;
|
||||
|
||||
public int CurrentSequence;
|
||||
public int FrameInSequence; // Current Sequence's Frame to Display
|
||||
|
||||
public bool IsActive;
|
||||
public bool IsSelected;
|
||||
|
||||
public readonly List<FGuid> AttachedModels;
|
||||
|
||||
public Animation()
|
||||
|
|
@ -30,13 +34,15 @@ public class Animation : IDisposable
|
|||
public Animation(string name, CAnimSet animSet) : this()
|
||||
{
|
||||
Name = name;
|
||||
TargetSkeleton = animSet.OriginalAnim.Name;
|
||||
|
||||
Sequences = new Sequence[animSet.Sequences.Count];
|
||||
for (int i = 0; i < Sequences.Length; i++)
|
||||
{
|
||||
Sequences[i] = new Sequence(animSet.Sequences[i]);
|
||||
|
||||
TotalElapsedTime += animSet.Sequences[i].NumFrames * Sequences[i].TimePerFrame;
|
||||
EndTime = Sequences[i].EndTime;
|
||||
TotalElapsedTime += animSet.Sequences[i].NumFrames * Sequences[i].TimePerFrame;
|
||||
}
|
||||
|
||||
if (Sequences.Length > 0)
|
||||
|
|
@ -83,9 +89,16 @@ public class Animation : IDisposable
|
|||
var p1 = new Vector2(timelineP0.X + StartTime * timeRatio.X + t, y + t);
|
||||
var p2 = new Vector2(timelineP0.X + EndTime * timeRatio.X - t, y + timeStep.Y - t);
|
||||
|
||||
drawList.AddRectFilled(p1, p2, 0xFF175F17, 5.0f, ImDrawFlags.RoundCornersTop);
|
||||
ImGui.SetCursorScreenPos(p1);
|
||||
ImGui.InvisibleButton($"timeline_sequencetracker_{Name}", new Vector2(EndTime * timeRatio.X - t, timeStep.Y - t), ImGuiButtonFlags.MouseButtonLeft);
|
||||
IsActive = ImGui.IsItemActive();
|
||||
|
||||
drawList.PushClipRect(treeP0, treeP1);
|
||||
drawList.AddRectFilled(p1, p2, IsSelected ? 0xFF48B048 : 0xFF175F17, 5.0f, ImDrawFlags.RoundCornersTop);
|
||||
drawList.PushClipRect(p1, p2, true);
|
||||
drawList.AddText(p1, 0xFF000000, $"{TargetSkeleton} - {CurrentSequence + 1}/{Sequences.Length} - {FrameInSequence}/{Sequences[CurrentSequence].EndFrame}");
|
||||
drawList.PopClipRect();
|
||||
|
||||
drawList.PushClipRect(treeP0 with { Y = p1.Y }, treeP1 with { Y = p2.Y }, true);
|
||||
drawList.AddText(treeP0 with { Y = y + timeStep.Y / 4.0f }, 0xFFFFFFFF, Name);
|
||||
drawList.PopClipRect();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ public class Sequence
|
|||
public readonly float EndTime;
|
||||
public readonly int EndFrame;
|
||||
public readonly int LoopingCount;
|
||||
public readonly bool IsAdditive;
|
||||
|
||||
public Sequence(CAnimSequence sequence)
|
||||
{
|
||||
|
|
@ -24,6 +25,7 @@ public class Sequence
|
|||
EndTime = StartTime + Duration;
|
||||
EndFrame = (Duration / TimePerFrame).FloorToInt() - 1;
|
||||
LoopingCount = sequence.LoopingCount;
|
||||
IsAdditive = sequence.bAdditive;
|
||||
}
|
||||
|
||||
private readonly float _height = 20.0f;
|
||||
|
|
|
|||
|
|
@ -92,15 +92,9 @@ public class Skeleton : IDisposable
|
|||
{
|
||||
for (int frame = 0; frame < _animatedBonesTransform[s][boneIndices.BoneIndex].Length; frame++)
|
||||
{
|
||||
// TODO: append the delta transform
|
||||
// ex: if bone 4, with parent 3, has its first found parent transform at 2,
|
||||
// we need to append the transform from 4 to 3 so that bone 4 won't be placed where bone 3 should be
|
||||
_animatedBonesTransform[s][boneIndices.BoneIndex][frame] = new Transform
|
||||
{
|
||||
Relation = _animatedBonesTransform[s][boneIndices.ParentTrackIndex][frame].Matrix,
|
||||
Rotation = originalTransform.Rotation,
|
||||
Position = originalTransform.Position,
|
||||
Scale = originalTransform.Scale
|
||||
Relation = originalTransform.LocalMatrix * _animatedBonesTransform[s][boneIndices.ParentTrackIndex][frame].Matrix
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -219,7 +213,7 @@ public class Skeleton : IDisposable
|
|||
do
|
||||
{
|
||||
var parentBoneIndices = BonesIndicesByLoweredName[loweredParentBoneName];
|
||||
if (parentBoneIndices.HasTrack) boneIndices.ParentTrackIndex = parentBoneIndices.BoneIndex;
|
||||
if (parentBoneIndices.HasTrack || parentBoneIndices.HasParentTrack) boneIndices.ParentTrackIndex = parentBoneIndices.BoneIndex;
|
||||
else loweredParentBoneName = parentBoneIndices.LoweredParentBoneName;
|
||||
} while (!boneIndices.HasParentTrack);
|
||||
}
|
||||
|
|
@ -255,7 +249,7 @@ public class Skeleton : IDisposable
|
|||
_previousSequenceFrame = frameInSequence;
|
||||
|
||||
_ssbo.Bind();
|
||||
for (int boneIndex = 0; boneIndex < BoneCount; boneIndex++)
|
||||
for (int boneIndex = 0; boneIndex < BoneCount; boneIndex++) // interpolate here
|
||||
_ssbo.Update(boneIndex, _invertedBonesMatrix[boneIndex] * _animatedBonesTransform[_previousAnimationSequence][boneIndex][_previousSequenceFrame].Matrix);
|
||||
_ssbo.Unbind();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,24 +59,26 @@ public class TimeTracker : IDisposable
|
|||
private const float _thickness = 2.0f;
|
||||
private const float _timeHeight = 10.0f;
|
||||
private float _timeBarHeight => _timeHeight * 2.0f;
|
||||
private readonly Vector2 _timeStep = new (50, 25);
|
||||
private readonly Vector2 _buttonSize = new (14.0f);
|
||||
private readonly string[] _icons = { "tl_forward", "tl_pause", "tl_rewind" };
|
||||
|
||||
public void ImGuiTimeline(Dictionary<string, Texture> icons, List<Animation> animations, Vector2 outliner, int activeAnimation, ImFontPtr fontPtr)
|
||||
public void ImGuiTimeline(Dictionary<string, Texture> icons, List<Animation> animations, Vector2 outliner, ref int activeAnimation, ImFontPtr fontPtr)
|
||||
{
|
||||
var treeP0 = ImGui.GetCursorScreenPos();
|
||||
var canvasSize = ImGui.GetContentRegionAvail();
|
||||
var timelineP1 = new Vector2(treeP0.X + canvasSize.X, treeP0.Y + canvasSize.Y);
|
||||
var canvasMaxY = MathF.Max(canvasSize.Y, _timeBarHeight + _timeStep.Y * animations.Count);
|
||||
ImGui.BeginChild("timeline_child", canvasSize with { Y = canvasMaxY });
|
||||
|
||||
var timelineP1 = new Vector2(treeP0.X + canvasSize.X, treeP0.Y + canvasMaxY);
|
||||
var treeP1 = timelineP1 with { X = treeP0.X + outliner.X };
|
||||
|
||||
var timelineP0 = treeP0 with { X = treeP1.X + _thickness };
|
||||
var timelineSize = timelineP1 - timelineP0;
|
||||
var timeRatio = timelineSize / MaxElapsedTime;
|
||||
var timeStep = timeRatio * MaxElapsedTime / timelineSize * 50.0f;
|
||||
timeStep.Y /= 2.0f;
|
||||
|
||||
var drawList = ImGui.GetWindowDrawList();
|
||||
drawList.PushClipRect(treeP0, timelineP1, true);
|
||||
drawList.AddRectFilled(treeP0, treeP1, 0xFF1F1C1C);
|
||||
drawList.AddRectFilled(timelineP0, timelineP1 with { Y = timelineP0.Y + _timeBarHeight }, 0xFF141414);
|
||||
drawList.AddRectFilled(timelineP0 with { Y = timelineP0.Y + _timeBarHeight }, timelineP1, 0xFF242424);
|
||||
|
|
@ -97,14 +99,14 @@ public class TimeTracker : IDisposable
|
|||
switch (i)
|
||||
{
|
||||
case 0:
|
||||
SafeSetElapsedTime(ElapsedTime + timeStep.X / timeRatio.X);
|
||||
SafeSetElapsedTime(ElapsedTime + _timeStep.X / timeRatio.X);
|
||||
break;
|
||||
case 1:
|
||||
IsPaused = !IsPaused;
|
||||
_icons[1] = IsPaused ? "tl_play" : "tl_pause";
|
||||
break;
|
||||
case 2:
|
||||
SafeSetElapsedTime(ElapsedTime - timeStep.X / timeRatio.X);
|
||||
SafeSetElapsedTime(ElapsedTime - _timeStep.X / timeRatio.X);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -124,7 +126,7 @@ public class TimeTracker : IDisposable
|
|||
}
|
||||
|
||||
{ // draw time + time grid
|
||||
for (float x = 0; x < timelineSize.X; x += timeStep.X)
|
||||
for (float x = 0; x < timelineSize.X; x += _timeStep.X)
|
||||
{
|
||||
var cursor = timelineP0.X + x;
|
||||
drawList.AddLine(new Vector2(cursor, timelineP0.Y + _timeHeight + 2.5f), new Vector2(cursor, timelineP0.Y + _timeBarHeight), 0xA0FFFFFF);
|
||||
|
|
@ -132,7 +134,7 @@ public class TimeTracker : IDisposable
|
|||
drawList.AddText(fontPtr, 14, new Vector2(cursor + 4, timelineP0.Y + 7.5f), 0x50FFFFFF, $"{x / timeRatio.X:F1}s");
|
||||
}
|
||||
|
||||
for (float y = _timeBarHeight; y < timelineSize.Y; y += timeStep.Y)
|
||||
for (float y = _timeBarHeight; y < timelineSize.Y; y += _timeStep.Y)
|
||||
{
|
||||
drawList.AddLine(timelineP0 with { Y = timelineP0.Y + y }, timelineP1 with { Y = timelineP0.Y + y }, 0x28C8C8C8);
|
||||
}
|
||||
|
|
@ -140,12 +142,20 @@ public class TimeTracker : IDisposable
|
|||
|
||||
for (int i = 0; i < animations.Count; i++)
|
||||
{
|
||||
var y = timelineP0.Y + _timeBarHeight + timeStep.Y * i;
|
||||
animations[i].ImGuiAnimation(drawList, timelineP0, treeP0, treeP1, timeStep, timeRatio, y, _thickness);
|
||||
DrawSeparator(drawList, timelineP0, y + timeStep.Y, animations[i].EndTime * timeRatio.X, ETrackerType.End);
|
||||
var y = timelineP0.Y + _timeBarHeight + _timeStep.Y * i;
|
||||
|
||||
animations[i].ImGuiAnimation(drawList, timelineP0, treeP0, treeP1, _timeStep, timeRatio, y, _thickness);
|
||||
animations[i].IsSelected = activeAnimation == i;
|
||||
if (ImGui.IsItemClicked(ImGuiMouseButton.Left))
|
||||
activeAnimation = i;
|
||||
|
||||
DrawSeparator(drawList, timelineP0, y + _timeStep.Y, animations[i].EndTime * timeRatio.X, ETrackerType.End);
|
||||
}
|
||||
|
||||
DrawSeparator(drawList, timelineP0, timelineP1.Y, ElapsedTime * timeRatio.X, ETrackerType.Frame);
|
||||
|
||||
drawList.PopClipRect();
|
||||
ImGui.EndChild();
|
||||
}
|
||||
|
||||
private void DrawSeparator(ImDrawListPtr drawList, Vector2 origin, float y, float time, ETrackerType separatorType)
|
||||
|
|
|
|||
|
|
@ -1,13 +1,12 @@
|
|||
using CUE4Parse_Conversion.Meshes.PSK;
|
||||
using CUE4Parse.UE4.Assets.Exports.Material;
|
||||
using CUE4Parse.UE4.Objects.Core.Misc;
|
||||
using FModel.Views.Snooper.Shading;
|
||||
|
||||
namespace FModel.Views.Snooper.Models;
|
||||
|
||||
public class Cube : Model
|
||||
{
|
||||
public Cube(CStaticMesh mesh, FGuid guid, UMaterialInterface unrealMaterial) : base(unrealMaterial, guid)
|
||||
public Cube(CStaticMesh mesh, UMaterialInterface unrealMaterial) : base(unrealMaterial)
|
||||
{
|
||||
var lod = mesh.LODs[0];
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ using CUE4Parse.UE4.Assets.Exports.Material;
|
|||
using CUE4Parse.UE4.Assets.Exports.SkeletalMesh;
|
||||
using CUE4Parse.UE4.Assets.Exports.StaticMesh;
|
||||
using CUE4Parse.UE4.Objects.Core.Math;
|
||||
using CUE4Parse.UE4.Objects.Core.Misc;
|
||||
using FModel.Extensions;
|
||||
using FModel.Settings;
|
||||
using FModel.Views.Snooper.Animations;
|
||||
|
|
@ -70,7 +69,6 @@ public class Model : IDisposable
|
|||
private const int _faceSize = 3;
|
||||
|
||||
private readonly UObject _export;
|
||||
public readonly FGuid Guid;
|
||||
public readonly string Path;
|
||||
public readonly string Name;
|
||||
public readonly string Type;
|
||||
|
|
@ -110,10 +108,9 @@ public class Model : IDisposable
|
|||
public int SelectedInstance;
|
||||
public float MorphTime;
|
||||
|
||||
protected Model(UObject export, FGuid guid)
|
||||
protected Model(UObject export)
|
||||
{
|
||||
_export = export;
|
||||
Guid = guid;
|
||||
Path = _export.GetPathName();
|
||||
Name = Path.SubstringAfterLast('/').SubstringBefore('.');
|
||||
Type = export.ExportType;
|
||||
|
|
@ -124,8 +121,8 @@ public class Model : IDisposable
|
|||
Transforms = new List<Transform>();
|
||||
}
|
||||
|
||||
public Model(UStaticMesh export, FGuid guid, CStaticMesh staticMesh) : this(export, guid, staticMesh, Transform.Identity) {}
|
||||
public Model(UStaticMesh export, FGuid guid, CStaticMesh staticMesh, Transform transform) : this(export, guid, export.Materials, staticMesh.LODs, transform)
|
||||
public Model(UStaticMesh export, CStaticMesh staticMesh) : this(export, staticMesh, Transform.Identity) {}
|
||||
public Model(UStaticMesh export, CStaticMesh staticMesh, Transform transform) : this(export, export.Materials, staticMesh.LODs, transform)
|
||||
{
|
||||
Box = staticMesh.BoundingBox * Constants.SCALE_DOWN_RATIO;
|
||||
|
||||
|
|
@ -136,8 +133,8 @@ public class Model : IDisposable
|
|||
}
|
||||
}
|
||||
|
||||
public Model(USkeletalMesh export, FGuid guid, CSkeletalMesh skeletalMesh) : this(export, guid, skeletalMesh, Transform.Identity) {}
|
||||
public Model(USkeletalMesh export, FGuid guid, CSkeletalMesh skeletalMesh, Transform transform) : this(export, guid, export.Materials, skeletalMesh.LODs, transform)
|
||||
public Model(USkeletalMesh export, CSkeletalMesh skeletalMesh) : this(export, skeletalMesh, Transform.Identity) {}
|
||||
public Model(USkeletalMesh export, CSkeletalMesh skeletalMesh, Transform transform) : this(export, export.Materials, skeletalMesh.LODs, transform)
|
||||
{
|
||||
Box = skeletalMesh.BoundingBox * Constants.SCALE_DOWN_RATIO;
|
||||
Skeleton = new Skeleton(export.ReferenceSkeleton);
|
||||
|
|
@ -163,11 +160,11 @@ public class Model : IDisposable
|
|||
}
|
||||
}
|
||||
|
||||
private Model(UObject export, FGuid guid, IReadOnlyList<ResolvedObject> materials, IReadOnlyList<CStaticMeshLod> lods, Transform transform = null)
|
||||
: this(export, guid, materials, lods[_LOD_INDEX], lods[_LOD_INDEX].Verts, lods.Count, transform) {}
|
||||
private Model(UObject export, FGuid guid, IReadOnlyList<ResolvedObject> materials, IReadOnlyList<CSkelMeshLod> lods, Transform transform = null)
|
||||
: this(export, guid, materials, lods[_LOD_INDEX], lods[_LOD_INDEX].Verts, lods.Count, transform) {}
|
||||
private Model(UObject export, FGuid guid, IReadOnlyList<ResolvedObject> materials, CBaseMeshLod lod, IReadOnlyList<CMeshVertex> vertices, int numLods, Transform transform = null) : this(export, guid)
|
||||
private Model(UObject export, IReadOnlyList<ResolvedObject> materials, IReadOnlyList<CStaticMeshLod> lods, Transform transform = null)
|
||||
: this(export, materials, lods[_LOD_INDEX], lods[_LOD_INDEX].Verts, lods.Count, transform) {}
|
||||
private Model(UObject export, IReadOnlyList<ResolvedObject> materials, IReadOnlyList<CSkelMeshLod> lods, Transform transform = null)
|
||||
: this(export, materials, lods[_LOD_INDEX], lods[_LOD_INDEX].Verts, lods.Count, transform) {}
|
||||
private Model(UObject export, IReadOnlyList<ResolvedObject> materials, CBaseMeshLod lod, IReadOnlyList<CMeshVertex> vertices, int numLods, Transform transform = null) : this(export)
|
||||
{
|
||||
var hasCustomUvs = lod.ExtraUV.IsValueCreated;
|
||||
UvCount = hasCustomUvs ? Math.Max(lod.NumTexCoords, numLods) : lod.NumTexCoords;
|
||||
|
|
@ -293,9 +290,9 @@ public class Model : IDisposable
|
|||
_morphVbo.Unbind();
|
||||
}
|
||||
|
||||
public void AttachModel(Model attachedTo, Socket socket)
|
||||
public void AttachModel(Model attachedTo, Socket socket, SocketAttachementInfo info)
|
||||
{
|
||||
socket.AttachedModels.Add(new SocketAttachementInfo { Guid = Guid, Instance = SelectedInstance });
|
||||
socket.AttachedModels.Add(info);
|
||||
|
||||
_attachedTo = $"'{socket.Name}' from '{attachedTo.Name}'{(!socket.BoneName.IsNone ? $" at '{socket.BoneName}'" : "")}";
|
||||
attachedTo._attachedFor.Add($"'{Name}'");
|
||||
|
|
@ -305,9 +302,9 @@ public class Model : IDisposable
|
|||
Transforms[SelectedInstance].Scale = FVector.OneVector;
|
||||
}
|
||||
|
||||
public void DetachModel(Model attachedTo, Socket socket)
|
||||
public void DetachModel(Model attachedTo, Socket socket, SocketAttachementInfo info)
|
||||
{
|
||||
socket.AttachedModels.Remove(new SocketAttachementInfo { Guid = Guid, Instance = SelectedInstance });
|
||||
socket.AttachedModels.Remove(info);
|
||||
SafeDetachModel(attachedTo);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ public class Options
|
|||
public FGuid SelectedModel { get; private set; }
|
||||
public int SelectedSection { get; private set; }
|
||||
public int SelectedMorph { get; private set; }
|
||||
public int SelectedAnimation { get; private set; }
|
||||
public int SelectedAnimation;
|
||||
|
||||
public readonly Dictionary<FGuid, Model> Models;
|
||||
public readonly Dictionary<FGuid, Texture> Textures;
|
||||
|
|
|
|||
|
|
@ -92,15 +92,11 @@ public class Renderer : IDisposable
|
|||
Options.SwapMaterial(false);
|
||||
}
|
||||
|
||||
public void Animate(UObject anim)
|
||||
public void Animate(UObject anim) => Animate(anim, Options.SelectedModel);
|
||||
private void Animate(UObject anim, FGuid guid)
|
||||
{
|
||||
if (!Options.TryGetModel(out var model))
|
||||
if (!Options.TryGetModel(guid, out var model) || !model.HasSkeleton)
|
||||
return;
|
||||
Animate(anim, model);
|
||||
}
|
||||
private void Animate(UObject anim, Model model)
|
||||
{
|
||||
if (!model.HasSkeleton) return;
|
||||
|
||||
float maxElapsedTime;
|
||||
switch (anim)
|
||||
|
|
@ -108,7 +104,7 @@ public class Renderer : IDisposable
|
|||
case UAnimSequence animSequence when animSequence.Skeleton.TryLoad(out USkeleton skeleton):
|
||||
{
|
||||
var animSet = skeleton.ConvertAnims(animSequence);
|
||||
var animation = new Animation(animSequence.Name, animSet, model.Guid);
|
||||
var animation = new Animation(animSequence.Name, animSet, guid);
|
||||
maxElapsedTime = animation.TotalElapsedTime;
|
||||
model.Skeleton.Animate(animSet, AnimateWithRotationOnly);
|
||||
Options.AddAnimation(animation);
|
||||
|
|
@ -117,7 +113,7 @@ public class Renderer : IDisposable
|
|||
case UAnimMontage animMontage when animMontage.Skeleton.TryLoad(out USkeleton skeleton):
|
||||
{
|
||||
var animSet = skeleton.ConvertAnims(animMontage);
|
||||
var animation = new Animation(animMontage.Name, animSet, model.Guid);
|
||||
var animation = new Animation(animMontage.Name, animSet, guid);
|
||||
maxElapsedTime = animation.TotalElapsedTime;
|
||||
model.Skeleton.Animate(animSet, AnimateWithRotationOnly);
|
||||
Options.AddAnimation(animation);
|
||||
|
|
@ -136,7 +132,6 @@ public class Renderer : IDisposable
|
|||
t.Scale = offset.Scale3D;
|
||||
}
|
||||
|
||||
FGuid guid;
|
||||
switch (export)
|
||||
{
|
||||
case UStaticMesh st:
|
||||
|
|
@ -145,14 +140,14 @@ public class Renderer : IDisposable
|
|||
if (Options.TryGetModel(guid, out var instancedModel))
|
||||
instancedModel.AddInstance(t);
|
||||
else if (st.TryConvert(out var mesh))
|
||||
Options.Models[guid] = new Model(st, guid, mesh, t);
|
||||
Options.Models[guid] = new Model(st, mesh, t);
|
||||
break;
|
||||
}
|
||||
case USkeletalMesh sk:
|
||||
{
|
||||
guid = new FGuid((uint) sk.GetFullName().GetHashCode());
|
||||
guid = Guid.NewGuid();
|
||||
if (!Options.Models.ContainsKey(guid) && sk.TryConvert(out var mesh))
|
||||
Options.Models[guid] = new Model(sk, guid, mesh, t);
|
||||
Options.Models[guid] = new Model(sk, mesh, t);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
|
@ -164,7 +159,7 @@ public class Renderer : IDisposable
|
|||
|
||||
addedModel.IsAnimatedProp = true;
|
||||
if (notifyClass.TryGetValue(out UObject skeletalMeshPropAnimation, "SkeletalMeshPropAnimation", "Animation"))
|
||||
Animate(skeletalMeshPropAnimation, addedModel);
|
||||
Animate(skeletalMeshPropAnimation, guid);
|
||||
if (notifyClass.TryGetValue(out FName socketName, "SocketName"))
|
||||
{
|
||||
t = Transform.Identity;
|
||||
|
|
@ -177,7 +172,7 @@ public class Renderer : IDisposable
|
|||
|
||||
var s = new Socket($"TL_{addedModel.Name}", socketName, t, true);
|
||||
model.Sockets.Add(s);
|
||||
addedModel.AttachModel(model, s);
|
||||
addedModel.AttachModel(model, s, new SocketAttachementInfo { Guid = guid, Instance = addedModel.SelectedInstance });
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
@ -185,7 +180,7 @@ public class Renderer : IDisposable
|
|||
case UAnimComposite animComposite when animComposite.Skeleton.TryLoad(out USkeleton skeleton):
|
||||
{
|
||||
var animSet = skeleton.ConvertAnims(animComposite);
|
||||
var animation = new Animation(animComposite.Name, animSet, model.Guid);
|
||||
var animation = new Animation(animComposite.Name, animSet, guid);
|
||||
maxElapsedTime = animation.TotalElapsedTime;
|
||||
model.Skeleton.Animate(animSet, AnimateWithRotationOnly);
|
||||
Options.AddAnimation(animation);
|
||||
|
|
@ -280,7 +275,7 @@ public class Renderer : IDisposable
|
|||
if (!original.TryConvert(out var mesh))
|
||||
return;
|
||||
|
||||
Options.Models[guid] = new Model(original, guid, mesh);
|
||||
Options.Models[guid] = new Model(original, mesh);
|
||||
Options.SelectModel(guid);
|
||||
SetupCamera(Options.Models[guid].Box);
|
||||
}
|
||||
|
|
@ -290,7 +285,7 @@ public class Renderer : IDisposable
|
|||
var guid = new FGuid((uint) original.GetFullName().GetHashCode());
|
||||
if (Options.Models.ContainsKey(guid) || !original.TryConvert(out var mesh)) return;
|
||||
|
||||
Options.Models[guid] = new Model(original, guid, mesh);
|
||||
Options.Models[guid] = new Model(original, mesh);
|
||||
Options.SelectModel(guid);
|
||||
SetupCamera(Options.Models[guid].Box);
|
||||
}
|
||||
|
|
@ -311,7 +306,7 @@ public class Renderer : IDisposable
|
|||
if (!editorCube.TryConvert(out var mesh))
|
||||
return;
|
||||
|
||||
Options.Models[guid] = new Cube(mesh, guid, original);
|
||||
Options.Models[guid] = new Cube(mesh, original);
|
||||
Options.SelectModel(guid);
|
||||
SetupCamera(Options.Models[guid].Box);
|
||||
}
|
||||
|
|
@ -403,7 +398,7 @@ public class Renderer : IDisposable
|
|||
}
|
||||
else if (m.TryConvert(out var mesh))
|
||||
{
|
||||
model = new Model(m, guid, mesh, t);
|
||||
model = new Model(m, mesh, t);
|
||||
model.TwoSided = actor.GetOrDefault("bMirrored", staticMeshComp.GetOrDefault("bDisallowMeshPaintPerInstance", model.TwoSided));
|
||||
|
||||
if (actor.TryGetValue(out FPackageIndex baseMaterial, "BaseMaterial") &&
|
||||
|
|
|
|||
|
|
@ -358,7 +358,7 @@ public class Material : IDisposable
|
|||
var canvasSize = ImGui.GetContentRegionAvail();
|
||||
if (canvasSize.X < 50.0f) canvasSize.X = 50.0f;
|
||||
if (canvasSize.Y < 50.0f) canvasSize.Y = 50.0f;
|
||||
var canvasP1 = new Vector2(canvasP0.X + canvasSize.X, canvasP0.Y + canvasSize.Y);
|
||||
var canvasP1 = canvasP0 + canvasSize;
|
||||
var origin = new Vector2(canvasP0.X + _scrolling.X, canvasP0.Y + _scrolling.Y);
|
||||
var absoluteMiddle = canvasSize / 2.0f;
|
||||
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ public class SnimGui
|
|||
|
||||
SectionWindow("Material Inspector", s.Renderer, DrawMaterialInspector, false);
|
||||
AnimationWindow("Timeline", s.Renderer, (icons, tracker, animations) =>
|
||||
tracker.ImGuiTimeline(icons, animations, _outlinerSize, s.Renderer.Options.SelectedAnimation, Controller.FontSemiBold));
|
||||
tracker.ImGuiTimeline(icons, animations, _outlinerSize, ref s.Renderer.Options.SelectedAnimation, Controller.FontSemiBold));
|
||||
|
||||
Window("World", () => DrawWorld(s), false);
|
||||
|
||||
|
|
@ -412,6 +412,7 @@ Snooper aims to give an accurate preview of models, materials, skeletal animatio
|
|||
{
|
||||
MeshWindow("Sockets", s.Renderer, (icons, selectedModel) =>
|
||||
{
|
||||
var info = new SocketAttachementInfo { Guid = s.Renderer.Options.SelectedModel, Instance = selectedModel.SelectedInstance };
|
||||
foreach (var model in s.Renderer.Options.Models.Values)
|
||||
{
|
||||
if (!model.HasSockets || model.IsSelected) continue;
|
||||
|
|
@ -420,16 +421,16 @@ Snooper aims to give an accurate preview of models, materials, skeletal animatio
|
|||
var i = 0;
|
||||
foreach (var socket in model.Sockets)
|
||||
{
|
||||
var isAttached = socket.AttachedModels.Contains(new SocketAttachementInfo { Guid = selectedModel.Guid, Instance = selectedModel.SelectedInstance });
|
||||
var isAttached = socket.AttachedModels.Contains(info);
|
||||
ImGui.PushID(i);
|
||||
ImGui.BeginDisabled(selectedModel.IsAttached && !isAttached);
|
||||
switch (isAttached)
|
||||
{
|
||||
case false when ImGui.Button($"Attach to '{socket.Name}'"):
|
||||
selectedModel.AttachModel(model, socket);
|
||||
selectedModel.AttachModel(model, socket, info);
|
||||
break;
|
||||
case true when ImGui.Button($"Detach from '{socket.Name}'"):
|
||||
selectedModel.DetachModel(model, socket);
|
||||
selectedModel.DetachModel(model, socket, info);
|
||||
break;
|
||||
}
|
||||
ImGui.EndDisabled();
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user