Skip to content

Commit

Permalink
Trying to get Dat animations working, but currently no luck yet.
Browse files Browse the repository at this point in the history
  • Loading branch information
MeltyPlayer committed Nov 5, 2023
1 parent 6f381a2 commit 0a22cb2
Show file tree
Hide file tree
Showing 12 changed files with 480 additions and 51 deletions.
60 changes: 60 additions & 0 deletions FinModelUtility/Fin/Fin/src/data/lazy/LazyList.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using System;
using System.Collections.Generic;
using System.Linq;

namespace fin.data.lazy {
public class LazyList<T> : ILazyArray<T> {
private readonly List<T> impl_ = new();
private readonly List<bool> populated_ = new();
private readonly Func<int, T> handler_;

public LazyList(Func<int, T> handler) {
this.handler_ = handler;
}

public LazyList(Func<LazyList<T>, int, T> handler) {
this.handler_ = (int key) => handler(this, key);
}

public int Count => this.impl_.Count;

public void Clear() {
this.impl_.Clear();
this.populated_.Clear();
}

public bool ContainsKey(int key) => this.populated_[key];


public T this[int key] {
get {
if (this.Count > key && this.populated_[key]) {
return this.impl_[key];
}

while (this.Count <= key) {
this.impl_.Add(default!);
this.populated_.Add(false);
}

this.populated_[key] = true;
return this.impl_[key] = this.handler_(key);
}
set {
while (this.Count <= key) {
this.impl_.Add(default!);
this.populated_.Add(false);
}

this.populated_[key] = true;
this.impl_[key] = value;
}
}

public IEnumerable<int> Keys
=> Enumerable.Range(0, this.Count).Where(this.ContainsKey);

public IEnumerable<T> Values
=> this.impl_.Where((value, i) => ContainsKey(i));
}
}
66 changes: 66 additions & 0 deletions FinModelUtility/Formats/Dat/Dat/src/api/DatBoneTracksHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
using dat.schema.animation;

using fin.model;

namespace dat.api {
public static class DatBoneTracksHelper {
public static void AddDatKeyframesToBoneTracks(
IEnumerable<IDatKeyframes> allDatKeyframes,
IBoneTracks boneTracks) {
var positionTrack = boneTracks.UseSeparatePositionAxesTrack();
var rotationTrack = boneTracks.UseEulerRadiansRotationTrack();
var scaleTrack = boneTracks.UseScaleTrack();

foreach (var datKeyframes in allDatKeyframes) {
var jointTrackType = datKeyframes.JointTrackType;
switch (jointTrackType) {
case JointTrackType.HSD_A_J_TRAX:
case JointTrackType.HSD_A_J_TRAY:
case JointTrackType.HSD_A_J_TRAZ: {
var axis = jointTrackType - JointTrackType.HSD_A_J_TRAX;
foreach (var keyframe in datKeyframes.Keyframes) {
var (frame, value, tangent) = keyframe;
positionTrack.Set(frame,
axis,
value,
tangent,
tangent);
}

break;
}
case JointTrackType.HSD_A_J_ROTX:
case JointTrackType.HSD_A_J_ROTY:
case JointTrackType.HSD_A_J_ROTZ: {
var axis = jointTrackType - JointTrackType.HSD_A_J_ROTX;
foreach (var keyframe in datKeyframes.Keyframes) {
var (frame, value, tangent) = keyframe;
rotationTrack.Set(frame,
axis,
value,
tangent,
tangent);
}

break;
}
case JointTrackType.HSD_A_J_SCAX:
case JointTrackType.HSD_A_J_SCAY:
case JointTrackType.HSD_A_J_SCAZ: {
var axis = jointTrackType - JointTrackType.HSD_A_J_SCAX;
foreach (var keyframe in datKeyframes.Keyframes) {
var (frame, value, tangent) = keyframe;
scaleTrack.Set(frame,
axis,
value,
tangent,
tangent);
}

break;
}
}
}
}
}
}
60 changes: 51 additions & 9 deletions FinModelUtility/Formats/Dat/Dat/src/api/DatModelImporter.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using dat.schema;
using dat.schema.animation;
using dat.schema.material;
using dat.schema.mesh;
using dat.schema.texture;
Expand Down Expand Up @@ -26,20 +27,22 @@
namespace dat.api {
public class DatModelImporter : IModelImporter<DatModelFileBundle> {
public unsafe IModel ImportModel(DatModelFileBundle modelFileBundle) {
var dat =
var primaryDat =
modelFileBundle.PrimaryDatFile.ReadNew<Dat>(Endianness.BigEndian);
var animationDat =
modelFileBundle.AnimationDatFile?.ReadNew<Dat>(Endianness.BigEndian);

var finModel = new ModelImpl();
var finSkin = finModel.Skin;

// Adds skeleton
var jObjByOffset = dat.JObjByOffset;
var jObjByOffset = primaryDat.JObjByOffset;
var finBoneByJObj = new Dictionary<JObj, IBone>();
var boneWeightsByJObj = new Dictionary<JObj, IBoneWeights>();
var inverseBindMatrixByJObj =
new Dictionary<JObj, IReadOnlyFinMatrix4x4>();
var boneQueue = new Queue<(IBone finParentBone, JObj datBone)>();
foreach (var datRootBone in dat.RootJObjs) {
foreach (var datRootBone in primaryDat.RootJObjs) {
boneQueue.Enqueue((finModel.Skeleton.Root, datRootBone));
}

Expand Down Expand Up @@ -77,16 +80,54 @@ public unsafe IModel ImportModel(DatModelFileBundle modelFileBundle) {
}

// Adds animations
foreach (var matAnimJoint in dat.MatAnimJoints) {
var matAnim = matAnimJoint.MatAnim;
if (animationDat != null) {
var lazyFinAnimations = new LazyList<IModelAnimation>(i => {
var finAnimation = finModel.AnimationManager.AddAnimation();
finAnimation.Name = $"Animation {i}";

finAnimation.FrameRate = 30;

return finAnimation;
});

var i = 0;
foreach (var figaTree in animationDat.GetRootNodesOfType<FigaTree>()) {
var finAnimation = lazyFinAnimations[i++];
finAnimation.FrameCount =
Math.Max(finAnimation.FrameCount, (int) figaTree.FrameCount);

foreach (var (jObj, trackNode) in primaryDat.JObjs.Zip(
figaTree.TrackNodes)) {
var finBone = finBoneByJObj[jObj];
var boneTracks = finAnimation.AddBoneTracks(finBone);
DatBoneTracksHelper.AddDatKeyframesToBoneTracks(trackNode, boneTracks);
}
}

/*foreach (var (jObj, matAnimJoint) in primaryDat.JObjs.Zip(
primaryDat.MatAnimJoints)) {
int i = 0;
foreach (var matAnim in matAnimJoint.MatAnims) {
var aObj = matAnim.AObj;
if (aObj != null) {
var finAnimation = lazyFinAnimations[i];
finAnimation.FrameCount =
Math.Max(finAnimation.FrameCount, (int) aObj.EndFrame);
var finBone = finBoneByJObj[jObj];
var boneTracks = finAnimation.AddBoneTracks(finBone);
;
}
i++;
}
}*/
}

// Adds mesh and materials
var mObjByOffset = new Dictionary<uint, MObj>();
var tObjByOffset = new Dictionary<uint, TObj>();
foreach (var jObj in dat.JObjs) {
foreach (var jObj in primaryDat.JObjs) {
foreach (var dObj in jObj.DObjs) {
var mObj = dObj.MObj;
if (mObj != null) {
Expand Down Expand Up @@ -270,8 +311,9 @@ public unsafe IModel ImportModel(DatModelFileBundle modelFileBundle) {

// Sorts all dObjs so that the opaque ones are rendered first, and then the translucent (XLU) ones
var allJObjsAndDObjs =
dat.JObjs.SelectMany(jObj => jObj.DObjs.Select(dObj => (jObj, dObj)))
.ToArray();
primaryDat
.JObjs.SelectMany(jObj => jObj.DObjs.Select(dObj => (jObj, dObj)))
.ToArray();
var sortedJObjsAndDObjs =
allJObjsAndDObjs
.Where(
Expand Down
62 changes: 30 additions & 32 deletions FinModelUtility/Formats/Dat/Dat/src/schema/Dat.cs
Original file line number Diff line number Diff line change
@@ -1,21 +1,15 @@
using dat.schema.animation;

using fin.data.queues;
using fin.math.matrix.four;
using fin.util.asserts;
using fin.util.enumerables;
using fin.util.hex;
using fin.util.linq;

using schema.binary;
using schema.binary.attributes;

namespace dat.schema {
// AObj: animation
// CObj: camera
// DObj: ?
// FObj: keyframe descriptor
// IObj: image
// JObj: joint (bone)
// SObj: Scene object

/// <summary>
Expand All @@ -32,7 +26,13 @@ public class Dat : IBinaryDeserializable {
private uint referenceNodeOffset_;
private uint stringTableOffset_;

public List<JObj> RootJObjs { get; } = new();
public List<IDatNode> RootNodes { get; } = new();

public IEnumerable<TNode> GetRootNodesOfType<TNode>()
where TNode : IDatNode
=> this.RootNodes.WhereIs<IDatNode, TNode>();

public IEnumerable<JObj> RootJObjs => this.GetRootNodesOfType<JObj>();

private readonly Dictionary<uint, JObj> jObjByOffset_ = new();
public IReadOnlyDictionary<uint, JObj> JObjByOffset => this.jObjByOffset_;
Expand All @@ -41,16 +41,8 @@ public class Dat : IBinaryDeserializable {
DatNodeExtensions.GetSelfAndChildrenAndSiblings);


public List<MatAnimJoint> RootMatAnimJoints { get; } = new();

public IEnumerable<MatAnimJoint> MatAnimJoints
=> this.RootMatAnimJoints.SelectMany(
DatNodeExtensions.GetSelfAndChildrenAndSiblings);


public void Read(IBinaryReader br) {
var fileHeader = br.ReadNew<FileHeader>();
Asserts.Equal(br.Length, fileHeader.FileSize);

this.dataBlockOffset_ = 0x20;
this.relocationTableOffset_ =
Expand Down Expand Up @@ -92,7 +84,7 @@ public void Read(IBinaryReader br) {

// Reads root bone structures
foreach (var rootNode in this.rootNodes_) {
if (rootNode.Type == RootNodeType.Undefined) {
if (rootNode.Type == RootNodeType.UNDEFINED) {
;
}
}
Expand All @@ -107,23 +99,25 @@ private void ReadRootNodeObjects_(IBinaryReader br) {

var jObjQueue = new FinTuple2Queue<uint, JObj>();

this.RootJObjs.Clear();
this.RootMatAnimJoints.Clear();
this.RootNodes.Clear();
foreach (var rootNode in this.rootNodes_) {
switch (rootNode.Type) {
case RootNodeType.JObj: {
var jObjOffset = rootNode.Data.DataOffset;
br.Position = jObjOffset;
var rootNodeOffset = rootNode.Data.DataOffset;
br.Position = rootNodeOffset;

switch (rootNode.Type) {
case RootNodeType.JOBJ: {
var jObj = br.ReadNew<JObj>();
this.RootJObjs.Add(jObj);
this.RootNodes.Add(jObj);

jObjQueue.Enqueue((jObjOffset, jObj));
jObjQueue.Enqueue((rootNodeOffset, jObj));
break;
}
case RootNodeType.MATANIM_JOINT: {
br.Position = rootNode.Data.DataOffset;
this.RootMatAnimJoints.Add(br.ReadNew<MatAnimJoint>());
this.RootNodes.Add(br.ReadNew<MatAnimJoint>());
break;
}
case RootNodeType.FIGATREE: {
this.RootNodes.Add(br.ReadNew<FigaTree>());
break;
}
}
Expand Down Expand Up @@ -226,10 +220,10 @@ public partial class RootNodeData : IBinaryConvertible {
}

public enum RootNodeType {
Undefined,
JObj,

UNDEFINED,
JOBJ,
MATANIM_JOINT,
FIGATREE,
IMAGE,
SCENE_DATA,
SCENE_MODELSET,
Expand All @@ -255,13 +249,17 @@ private static RootNodeType GetTypeFromName_(string name) {
// TODO: Use flags for this instead
if (name.EndsWith("_joint") && !name.Contains("matanim") &&
!name.Contains("anim_joint")) {
return RootNodeType.JObj;
return RootNodeType.JOBJ;
}

if (name.EndsWith("_matanim_joint")) {
return RootNodeType.MATANIM_JOINT;
}

if (name.EndsWith("_figatree")) {
return RootNodeType.FIGATREE;
}

if (name.EndsWith("_image")) {
return RootNodeType.IMAGE;
}
Expand All @@ -282,7 +280,7 @@ private static RootNodeType GetTypeFromName_(string name) {
return RootNodeType.TLUT_DESC;
}

return RootNodeType.Undefined;
return RootNodeType.UNDEFINED;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
namespace dat.schema {
public interface IDatLinkedListNode<out TSelf>
public interface IDatNode;

public interface IDatLinkedListNode<out TSelf> : IDatNode
where TSelf : IDatLinkedListNode<TSelf> {
TSelf? NextSibling { get; }
}

public interface IDatTreeNode<out TSelf>
: IDatLinkedListNode<TSelf>
public interface IDatTreeNode<out TSelf> : IDatLinkedListNode<TSelf>
where TSelf : IDatTreeNode<TSelf> {
TSelf? FirstChild { get; }
}
Expand Down
Loading

0 comments on commit 0a22cb2

Please sign in to comment.