From 91873ea87aa100b16b62b6cfba7d20791d6a388e Mon Sep 17 00:00:00 2001 From: dexy Date: Tue, 26 Nov 2019 17:00:41 +1100 Subject: [PATCH] Peds no longer sharing skeletons, Cutscene object AnimHash conflict resolution --- .../GameFiles/Resources/Drawable.cs | 202 +++++++++++++++--- CodeWalker.Core/World/Ped.cs | 4 + Rendering/Renderable.cs | 41 ++-- Rendering/Renderer.cs | 2 +- Rendering/Shaders/BasicShader.cs | 4 +- Rendering/Shaders/ShadowShader.cs | 4 +- World/CutsceneForm.cs | 29 ++- 7 files changed, 215 insertions(+), 71 deletions(-) diff --git a/CodeWalker.Core/GameFiles/Resources/Drawable.cs b/CodeWalker.Core/GameFiles/Resources/Drawable.cs index e622573..e26dab8 100644 --- a/CodeWalker.Core/GameFiles/Resources/Drawable.cs +++ b/CodeWalker.Core/GameFiles/Resources/Drawable.cs @@ -510,7 +510,7 @@ namespace CodeWalker.GameFiles // structure data public uint VFT { get; set; } - public uint Unknown_4h { get; set; } // 0x00000001 + public uint Unknown_4h { get; set; } = 1; // 0x00000001 public uint Unknown_8h { get; set; } // 0x00000000 public uint Unknown_Ch { get; set; } // 0x00000000 public ulong BoneTagsPointer { get; set; } @@ -527,7 +527,7 @@ namespace CodeWalker.GameFiles public MetaHash Unknown_50h { get; set; } public MetaHash Unknown_54h { get; set; } public MetaHash Unknown_58h { get; set; } - public ushort Unknown_5Ch { get; set; } // 0x0001 + public ushort Unknown_5Ch { get; set; } = 1; // 0x0001 public ushort BonesCount { get; set; } public ushort ChildIndicesCount { get; set; } public ushort Unknown_62h { get; set; } // 0x0000 @@ -553,6 +553,9 @@ namespace CodeWalker.GameFiles public Dictionary BonesMap { get; set; }//for convienience finding bones by tag + public Matrix3_s[] BoneTransforms; //for rendering + + /// /// Reads the data-block from a stream. @@ -601,35 +604,9 @@ namespace CodeWalker.GameFiles this.ChildIndices = reader.ReadShortsAt(this.ChildIndicesPointer, this.ChildIndicesCount); - if ((Bones != null) && (ParentIndices != null)) - { - var maxcnt = Math.Min(Bones.Count, ParentIndices.Length); - for (int i = 0; i < maxcnt; i++) - { - var bone = Bones[i]; - var pind = ParentIndices[i]; - if ((pind >= 0) && (pind < Bones.Count)) - { - bone.Parent = Bones[pind]; - } - } - } - - BonesMap = new Dictionary(); - if (Bones != null) - { - for (int i = 0; i < Bones.Count; i++) - { - var bone = Bones[i]; - BonesMap[bone.Tag] = bone; - - bone.UpdateAnimTransform(); - bone.BindTransformInv = (i < TransformationsInverted?.Length) ? TransformationsInverted[i] : Matrix.Invert(bone.AnimTransform); - bone.BindTransformInv.M44 = 1.0f; - bone.UpdateSkinTransform(); - } - } + AssignBoneParents(); + BuildBonesMap(); } /// @@ -708,6 +685,165 @@ namespace CodeWalker.GameFiles } return list.ToArray(); } + + + + + + + public void AssignBoneParents() + { + if ((Bones != null) && (ParentIndices != null)) + { + var maxcnt = Math.Min(Bones.Count, ParentIndices.Length); + for (int i = 0; i < maxcnt; i++) + { + var bone = Bones[i]; + var pind = ParentIndices[i]; + if ((pind >= 0) && (pind < Bones.Count)) + { + bone.Parent = Bones[pind]; + } + } + } + } + + public void BuildBonesMap() + { + BonesMap = new Dictionary(); + if (Bones != null) + { + for (int i = 0; i < Bones.Count; i++) + { + var bone = Bones[i]; + BonesMap[bone.Tag] = bone; + + bone.UpdateAnimTransform(); + bone.BindTransformInv = (i < TransformationsInverted?.Length) ? TransformationsInverted[i] : Matrix.Invert(bone.AnimTransform); + bone.BindTransformInv.M44 = 1.0f; + bone.UpdateSkinTransform(); + } + } + } + + + + public void ResetBoneTransforms() + { + if (Bones?.Data == null) return; + foreach (var bone in Bones.Data) + { + bone.ResetAnimTransform(); + } + UpdateBoneTransforms(); + } + public void UpdateBoneTransforms() + { + if (Bones?.Data == null) return; + if ((BoneTransforms == null) || (BoneTransforms.Length != Bones.Data.Count)) + { + BoneTransforms = new Matrix3_s[Bones.Data.Count]; + } + for (int i = 0; i < Bones.Data.Count; i++) + { + var bone = Bones.Data[i]; + Matrix b = bone.SkinTransform; + Matrix3_s bt = new Matrix3_s(); + bt.Row1 = b.Column1; + bt.Row2 = b.Column2; + bt.Row3 = b.Column3; + BoneTransforms[i] = bt; + } + } + + + + + + + public Skeleton Clone() + { + var skel = new Skeleton(); + + skel.Count1 = Count1; + skel.Count2 = Count2; + skel.Unknown_1Ch = Unknown_1Ch; + skel.Unknown_50h = Unknown_50h; + skel.Unknown_54h = Unknown_54h; + skel.Unknown_58h = Unknown_58h; + skel.BonesCount = BonesCount; + skel.ChildIndicesCount = ChildIndicesCount; + + if (BoneTags != null) + { + skel.BoneTags = new ResourcePointerArray64(); + if (BoneTags.data_items != null) + { + skel.BoneTags.data_items = new SkeletonBoneTag[BoneTags.data_items.Length]; + for (int i = 0; i < BoneTags.data_items.Length; i++) + { + var obt = BoneTags.data_items[i]; + var nbt = new SkeletonBoneTag(); + skel.BoneTags.data_items[i] = nbt; + while (obt != null) + { + nbt.BoneTag = obt.BoneTag; + nbt.BoneIndex = obt.BoneIndex; + obt = obt.LinkedTag; + if (obt != null) + { + var nxt = new SkeletonBoneTag(); + nbt.LinkedTag = nxt; + nbt = nxt; + } + } + } + } + } + if (Bones != null) + { + skel.Bones = new ResourceSimpleArray(); + if (Bones.Data != null) + { + skel.Bones.Data = new List(); + for (int i = 0; i < Bones.Data.Count; i++) + { + var ob = Bones.Data[i]; + var nb = new Bone(); + nb.Rotation = ob.Rotation; + nb.Translation = ob.Translation; + nb.Scale = ob.Scale; + nb.NextSiblingIndex = ob.NextSiblingIndex; + nb.ParentIndex = ob.ParentIndex; + nb.Flags = ob.Flags; + nb.Index = ob.Index; + nb.Tag = ob.Tag; + nb.Index2 = ob.Index2; + nb.Name = ob.Name; + nb.AnimRotation = ob.AnimRotation; + nb.AnimTranslation = ob.AnimTranslation; + nb.AnimScale = ob.AnimScale; + nb.AnimTransform = ob.AnimTransform; + nb.BindTransformInv = ob.BindTransformInv; + nb.SkinTransform = ob.SkinTransform; + skel.Bones.Data.Add(nb); + } + } + } + + skel.TransformationsInverted = (Matrix[])TransformationsInverted.Clone(); + skel.Transformations = (Matrix[])Transformations.Clone(); + skel.ParentIndices = (short[])ParentIndices.Clone(); + skel.ChildIndices = (short[])ChildIndices.Clone(); + + skel.AssignBoneParents(); + skel.BuildBonesMap(); + + return skel; + } + + + } [TypeConverter(typeof(ExpandableObjectConverter))] public class SkeletonBoneTag : ResourceSystemBlock @@ -800,15 +936,11 @@ namespace CodeWalker.GameFiles } // structure data - //public float RotationX { get; set; } - //public float RotationY { get; set; } - //public float RotationZ { get; set; } - //public float RotationW { get; set; } public Quaternion Rotation { get; set; } public Vector3 Translation { get; set; } public uint Unknown_1Ch { get; set; } // 0x00000000 RHW? public Vector3 Scale { get; set; } - public float Unknown_2Ch { get; set; } // 1.0 RHW? + public float Unknown_2Ch { get; set; } = 1.0f; // 1.0 RHW? public short NextSiblingIndex { get; set; } //limb end index? IK chain? public short ParentIndex { get; set; } public uint Unknown_34h { get; set; } // 0x00000000 diff --git a/CodeWalker.Core/World/Ped.cs b/CodeWalker.Core/World/Ped.cs index 75afe0b..09df2d0 100644 --- a/CodeWalker.Core/World/Ped.cs +++ b/CodeWalker.Core/World/Ped.cs @@ -29,11 +29,13 @@ namespace CodeWalker.World public Drawable[] Drawables { get; set; } = new Drawable[12]; public Texture[] Textures { get; set; } = new Texture[12]; public bool EnableRootMotion { get; set; } = false; //used to toggle whether or not to include root motion when playing animations + public Skeleton Skeleton { get; set; } = null; public Vector3 Position { get; set; } = Vector3.Zero; public Quaternion Rotation { get; set; } = Quaternion.Identity; + public void Init(string name, GameFileCache gfc) { var hash = JenkHash.GenHash(name.ToLowerInvariant()); @@ -108,6 +110,8 @@ namespace CodeWalker.World } + Skeleton = Yft?.Fragment?.Drawable?.Skeleton?.Clone(); + MetaHash cliphash = JenkHash.GenHash("idle"); ClipMapEntry cme = null; Ycd?.ClipMap?.TryGetValue(cliphash, out cme); diff --git a/Rendering/Renderable.cs b/Rendering/Renderable.cs index f595d4b..a713f04 100644 --- a/Rendering/Renderable.cs +++ b/Rendering/Renderable.cs @@ -68,6 +68,7 @@ namespace CodeWalker.Rendering //public Dictionary TextureDict { get; private set; } //public long EmbeddedTextureSize { get; private set; } + public Skeleton Skeleton { get; set; } = null; public bool HasSkeleton; public bool HasTransforms; @@ -77,8 +78,6 @@ namespace CodeWalker.Rendering public ClipMapEntry ClipMapEntry; public Dictionary ModelBoneLinks; - public Matrix3_s[] BoneTransforms; - public List Bones; public bool EnableRootMotion = false; //used to toggle whether or not to include root motion when playing animations @@ -240,7 +239,7 @@ namespace CodeWalker.Rendering HasSkeleton = hasskeleton; HasTransforms = hastransforms; - Bones = skeleton?.Bones?.Data; + Skeleton = skeleton; //calculate transforms for the models if there are any. (TODO: move this to a method for re-use...) @@ -362,30 +361,18 @@ namespace CodeWalker.Rendering public void ResetBoneTransforms() { - if (Bones == null) return; - foreach (var bone in Bones) - { - bone.ResetAnimTransform(); - } + if (Skeleton == null) return; + Skeleton.ResetBoneTransforms(); UpdateBoneTransforms(); } private void UpdateBoneTransforms() { - if (Bones == null) return; - if ((BoneTransforms == null) || (BoneTransforms.Length != Bones.Count)) - { - BoneTransforms = new Matrix3_s[Bones.Count]; - } - for (int i = 0; i < Bones.Count; i++) - { - var bone = Bones[i]; - Matrix b = bone.SkinTransform; - Matrix3_s bt = new Matrix3_s(); - bt.Row1 = b.Column1; - bt.Row2 = b.Column2; - bt.Row3 = b.Column3; - BoneTransforms[i] = bt; - } + if (Skeleton?.Bones?.Data == null) return; + + Skeleton.UpdateBoneTransforms(); + + var bones = Skeleton.Bones?.Data; + var bonetransforms = Skeleton.BoneTransforms; var drawbl = Key; if (AllModels == null) return; @@ -398,7 +385,7 @@ namespace CodeWalker.Rendering var geom = model.Geometries[g]; var boneids = geom?.DrawableGeom?.BoneIds; if (boneids == null) continue; - if (boneids.Length != Bones.Count) + if (boneids.Length != bones.Count) { var idc = boneids.Length; if (geom.BoneTransforms == null) @@ -408,9 +395,9 @@ namespace CodeWalker.Rendering for (int b = 0; b < idc; b++) { var id = boneids[b]; - if (id < BoneTransforms.Length) + if (id < bonetransforms.Length) { - geom.BoneTransforms[b] = BoneTransforms[id]; + geom.BoneTransforms[b] = bonetransforms[id]; if (id != b) { } } @@ -492,7 +479,7 @@ namespace CodeWalker.Rendering var frame = anim.GetFramePosition(t); var dwbl = this.Key; - var skel = dwbl?.Skeleton; + var skel = Skeleton; var bones = skel?.Bones; if (bones == null) { return; } diff --git a/Rendering/Renderer.cs b/Rendering/Renderer.cs index 8e9c7fd..b221527 100644 --- a/Rendering/Renderer.cs +++ b/Rendering/Renderer.cs @@ -2785,7 +2785,7 @@ namespace CodeWalker.Rendering ac.EnableRootMotion = ped.EnableRootMotion; } - var skel = ped.Yft?.Fragment?.Drawable?.Skeleton; + var skel = ped.Skeleton; if (skel != null) { if (drawable.Skeleton == null) diff --git a/Rendering/Shaders/BasicShader.cs b/Rendering/Shaders/BasicShader.cs index d18db4c..1e17935 100644 --- a/Rendering/Shaders/BasicShader.cs +++ b/Rendering/Shaders/BasicShader.cs @@ -574,9 +574,9 @@ namespace CodeWalker.Rendering public override void SetModelVars(DeviceContext context, RenderableModel model) { - if (model.Owner.BoneTransforms != null) + if (model.Owner.Skeleton?.BoneTransforms != null) { - SetBoneMatrices(context, model.Owner.BoneTransforms); + SetBoneMatrices(context, model.Owner.Skeleton.BoneTransforms); defaultBoneMatricesBound = false; } else if (!defaultBoneMatricesBound) diff --git a/Rendering/Shaders/ShadowShader.cs b/Rendering/Shaders/ShadowShader.cs index e1d7570..2474b99 100644 --- a/Rendering/Shaders/ShadowShader.cs +++ b/Rendering/Shaders/ShadowShader.cs @@ -233,9 +233,9 @@ namespace CodeWalker.Rendering public override void SetModelVars(DeviceContext context, RenderableModel model) { - if (model.Owner.BoneTransforms != null) + if (model.Owner.Skeleton?.BoneTransforms != null) { - SetBoneMatrices(context, model.Owner.BoneTransforms); + SetBoneMatrices(context, model.Owner.Skeleton.BoneTransforms); defaultBoneMatricesBound = false; } else if (!defaultBoneMatricesBound) diff --git a/World/CutsceneForm.cs b/World/CutsceneForm.cs index ad9321b..99c7ac1 100644 --- a/World/CutsceneForm.cs +++ b/World/CutsceneForm.cs @@ -469,7 +469,7 @@ namespace CodeWalker.World { if (obj.Ped != null) { - ycd.CutsceneMap.TryGetValue(obj.Ped.NameHash, out cme); + ycd.CutsceneMap.TryGetValue(obj.AnimHash, out cme); var pos = Position; var rot = Rotation; if (cme != null) @@ -488,7 +488,7 @@ namespace CodeWalker.World } if (obj.Prop != null) { - ycd.CutsceneMap.TryGetValue(obj.Prop.Archetype?.Hash ?? 0, out cme); + ycd.CutsceneMap.TryGetValue(obj.AnimHash, out cme); var pos = Position; var rot = Rotation; if (cme != null) @@ -989,11 +989,29 @@ namespace CodeWalker.World if (Objects == null) return; + + var refCounts = new Dictionary(); + foreach (var obj in Objects.Values) { var sobj = new CutsceneObject(); sobj.Init(obj, GameFileCache); SceneObjects[sobj.ObjectID] = sobj; + + if (sobj.AnimHash != 0) + { + int refcount = 0; + var hash = sobj.AnimHash; + refCounts.TryGetValue(hash, out refcount); + if (refcount > 0) + { + var newstr = hash.ToString() + "^" + refcount.ToString(); + sobj.AnimHash = JenkHash.GenHash(newstr); + } + refcount++; + refCounts[hash] = refcount; + } + } } } @@ -1011,6 +1029,7 @@ namespace CodeWalker.World public YmapEntityDef Prop { get; set; } + public MetaHash AnimHash { get; set; } public ClipMapEntry AnimClip { get; set; } @@ -1107,15 +1126,17 @@ namespace CodeWalker.World Ped.SetComponentDrawable(4, 19, 0, 0, gfc); Ped.SetComponentDrawable(6, null, null, gfc); } + + AnimHash = ped.StreamingName; } private void InitProp(CutPropModelObject prop, GameFileCache gfc) { - var archetypeName = prop.StreamingName; Prop = new YmapEntityDef(); - Prop.SetArchetype(gfc.GetArchetype(archetypeName)); + Prop.SetArchetype(gfc.GetArchetype(prop.StreamingName)); + AnimHash = prop.StreamingName; } private void InitVehicle(CutVehicleModelObject veh, GameFileCache gfc)