Skip to content

Commit

Permalink
Add support for Internal Skin Param (#52)
Browse files Browse the repository at this point in the history
* Add support for Internal Skin Param

* Simplify casting of block type

* Write osage block external name to skp instead of internal name

* Set internal skp name to ExternalName of osgBlock on creation

* Fix mistake regarding Tail of OsageInternalCollisionParameter
  • Loading branch information
thtrandomlurker authored Feb 21, 2024
1 parent 3202172 commit f0e5ebc
Show file tree
Hide file tree
Showing 5 changed files with 453 additions and 14 deletions.
14 changes: 11 additions & 3 deletions MikuMikuLibrary/Objects/Extra/Blocks/ClothBlock.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using MikuMikuLibrary.IO;
using MikuMikuLibrary.IO.Common;
using MikuMikuLibrary.Objects.Extra.Parameters;

namespace MikuMikuLibrary.Objects.Extra.Blocks;

Expand All @@ -17,7 +18,7 @@ public class ClothBlock : IBlock
public List<Field20Data> Field20 { get; set; }
public ushort[] Field24 { get; set; }
public ushort[] Field28 { get; set; }
public uint Field2C { get; set; }
public OsageInternalSkinParameter InternalSkinParameter { get; set; }
public uint Field30 { get; set; }

public void Read(EndianBinaryReader reader, StringSet stringSet)
Expand Down Expand Up @@ -66,7 +67,11 @@ public void Read(EndianBinaryReader reader, StringSet stringSet)

reader.ReadOffset(() => { Field28 = reader.ReadUInt16s(reader.ReadUInt16()); });

Field2C = reader.ReadUInt32();
reader.ReadOffset(() =>
{
InternalSkinParameter = new OsageInternalSkinParameter();
InternalSkinParameter.Read(reader);
});
Field30 = reader.ReadUInt32();
}

Expand Down Expand Up @@ -112,7 +117,10 @@ public void Write(EndianBinaryWriter writer, StringSet stringSet, BinaryFormat f
writer.Write(Field28);
});

writer.Write(Field2C);
writer.WriteOffsetIf(InternalSkinParameter != null, 16, AlignmentMode.Left, () =>
{
InternalSkinParameter.Write(writer);
});
writer.Write(Field30);
}

Expand Down
48 changes: 37 additions & 11 deletions MikuMikuLibrary/Objects/Extra/Blocks/OsageBlock.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using MikuMikuLibrary.IO;
using MikuMikuLibrary.IO.Common;
using MikuMikuLibrary.Objects.Extra.Parameters;

namespace MikuMikuLibrary.Objects.Extra.Blocks;

Expand All @@ -12,6 +13,7 @@ public class OsageBlock : NodeBlock

public List<OsageNode> Nodes { get; }
public string ExternalName { get; set; }
public OsageInternalSkinParameter InternalSkinParameter { get; set; }

internal override void ReadBody(EndianBinaryReader reader, StringSet stringSet)
{
Expand All @@ -29,15 +31,21 @@ internal override void ReadBody(EndianBinaryReader reader, StringSet stringSet)
reader.ReadOffset(() =>
{
long current = reader.Position;
if (reader.ReadUInt32() == 0)
{
if (reader.ReadUInt32() == 0) // Integrated SKP, yet to support.
return;
// read the internal skin param
reader.SeekBegin(current);
InternalSkinParameter = new OsageInternalSkinParameter();
InternalSkinParameter.Read(reader);
}
else
{
// read rotation
reader.SeekBegin(current);

reader.SeekBegin(current);

foreach (var bone in Nodes)
bone.ReadOsgBlockInfo(reader, stringSet);
foreach (var bone in Nodes)
bone.ReadOsgBlockInfo(reader, stringSet);
}
});

if (reader.AddressSpace == AddressSpace.Int64)
Expand All @@ -53,16 +61,34 @@ internal override void WriteBody(EndianBinaryWriter writer, StringSet stringSet,
stringSet.WriteString(writer, ExternalName);
stringSet.WriteString(writer, Name);

bool shouldWriteRotation = format == BinaryFormat.FT && Nodes.Any(x =>
bool shouldWriteRotation = Nodes.Any(x =>
Math.Abs(x.Rotation.X) > 0 ||
Math.Abs(x.Rotation.Y) > 0 ||
Math.Abs(x.Rotation.Z) > 0);

writer.WriteOffsetIf(shouldWriteRotation, 4, AlignmentMode.Left, () =>
bool shouldWriteInternalSkinParam = InternalSkinParameter != null;

if (format == BinaryFormat.FT)
{
foreach (var bone in Nodes)
bone.WriteOsgBlockInfo(writer, stringSet);
});
writer.WriteOffsetIf(shouldWriteRotation, 4, AlignmentMode.Left, () =>
{
foreach (var bone in Nodes)
bone.WriteOsgBlockInfo(writer, stringSet);
});
}

else if (format == BinaryFormat.DT)
{
writer.WriteOffsetIf(shouldWriteInternalSkinParam, 16, AlignmentMode.Left, () =>
{
InternalSkinParameter.Write(writer);
});
}

else
{
writer.WriteOffsetIf(false, () => { });
}

if (writer.AddressSpace == AddressSpace.Int64)
writer.WriteNulls(4 * sizeof(ulong));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
using MikuMikuLibrary.IO.Common;

namespace MikuMikuLibrary.Objects.Extra.Parameters;

public enum OsageInternalCollisionType : int
{
End = 0,
Sphere = 1,
Cylinder = 2,
Plane = 3,
Ellipse = 4
}

public class OsageInternalCollisionParameter
{
public OsageInternalCollisionType CollisionType { get; set; }
public uint Head { get; set; }
public uint Tail { get; set; }
public float CollisionRadius { get; set; }
public Vector3 HeadPosition { get; set; }
public Vector3 TailPosition { get; set; }

internal void Read(EndianBinaryReader reader)
{
CollisionType = (OsageInternalCollisionType)reader.ReadInt32();
Head = reader.ReadUInt32();
Tail = reader.ReadUInt32();
CollisionRadius = reader.ReadSingle();
HeadPosition = reader.ReadVector3();
TailPosition = reader.ReadVector3();
}

internal void Write(EndianBinaryWriter writer)
{
writer.Write((int)CollisionType);
writer.Write(Head);
writer.Write(Tail);
writer.Write(CollisionRadius);
writer.Write(HeadPosition);
writer.Write(TailPosition);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
using MikuMikuLibrary.IO;
using MikuMikuLibrary.IO.Common;
using MikuMikuLibrary.Parameters;

namespace MikuMikuLibrary.Objects.Extra.Parameters;


[TypeConverter(typeof(ExpandableObjectConverter))]
public class OsageInternalSkinParameter
{
public string Name { get; set; }
public float Force { get; set; }
public float ForceGain { get; set; }
public float AirResistance { get; set; }
public float RotationY { get; set; }
public float RotationZ { get; set; }
public float HingeY { get; set; }
public float HingeZ { get; set; }
public float CollisionRadius { get; set; }
public float Friction { get; set; }
public float WindAffection { get; set; }
public List<OsageInternalCollisionParameter> Collisions { get; }

internal void Read(EndianBinaryReader reader)
{
long start = reader.Position;
reader.SkipNulls(4); // Truthfully, i don't know if this is inertial_cancel or just a reserved field. it seems to always be 0 though so i won't read it.
// Besides, if i did read and write it, and someone wrote it as anything but 0, then it would from that point on be falsely read as FT, which wouldn't be good.

Force = reader.ReadSingle();
ForceGain = reader.ReadSingle();
AirResistance = reader.ReadSingle();
RotationY = reader.ReadSingle();
RotationZ = reader.ReadSingle();
HingeY = reader.ReadSingle();
HingeZ = reader.ReadSingle();
Name = reader.ReadStringOffset(StringBinaryFormat.NullTerminated);

reader.ReadOffset(() =>
{
while (true)
{
OsageInternalCollisionParameter collisionParameter = new OsageInternalCollisionParameter();
collisionParameter.Read(reader);
if (collisionParameter.CollisionType == OsageInternalCollisionType.End)
{
break;
}
Collisions.Add(collisionParameter);

};
});

CollisionRadius = reader.ReadSingle();
Friction = reader.ReadSingle();
WindAffection = reader.ReadSingle();
}

internal void Write(EndianBinaryWriter writer)
{
writer.WriteNulls(4);
writer.Write(Force);
writer.Write(ForceGain);
writer.Write(AirResistance);
writer.Write(RotationY);
writer.Write(RotationZ);
writer.Write(HingeY);
writer.Write(HingeZ);
writer.WriteStringOffset(Name);
writer.WriteOffset(16, AlignmentMode.Left, () =>
{
foreach (var coll in Collisions)
{
coll.Write(writer);
}

new OsageInternalCollisionParameter() { CollisionType = OsageInternalCollisionType.End }.Write(writer); // please suggest a better way to handle this
});
writer.Write(CollisionRadius);
writer.Write(Friction);
writer.Write(WindAffection);
}

public OsageInternalSkinParameter()
{
Collisions = new List<OsageInternalCollisionParameter>();
}
}
Loading

0 comments on commit f0e5ebc

Please sign in to comment.