1
0
mirror of synced 2024-11-30 18:24:39 +01:00

Add support for G1M model files. Rewrite some bone properties.

This commit is contained in:
KillzXGaming 2020-02-06 19:47:32 -05:00
parent f87487cad4
commit d991a23980
49 changed files with 2062 additions and 1227 deletions

View File

@ -41,19 +41,18 @@ namespace FirstPlugin.CtrLibrary
parentIndex = bone.ParentIndex; parentIndex = bone.ParentIndex;
RotationType = BoneRotationType.Euler; RotationType = BoneRotationType.Euler;
position = new float[3]; Position = new OpenTK.Vector3(
scale = new float[3]; bone.Translation.X,
rotation = new float[4]; bone.Translation.Y,
scale[0] = bone.Scale.X; bone.Translation.Z);
scale[1] = bone.Scale.Y; EulerRotation = new OpenTK.Vector3(
scale[2] = bone.Scale.Z; bone.Rotation.X,
rotation[0] = bone.Rotation.X; bone.Rotation.Y,
rotation[1] = bone.Rotation.Y; bone.Rotation.Z);
rotation[2] = bone.Rotation.Z; Scale = new OpenTK.Vector3(
rotation[3] = 1; bone.Scale.X,
position[0] = bone.Translation.X; bone.Scale.Y,
position[1] = bone.Translation.Y; bone.Scale.Z);
position[2] = bone.Translation.Z;
} }
} }
} }

View File

@ -49,15 +49,20 @@ namespace Bfres.Structs
{ {
case ResU.AnimCurveType.Cubic: //4 elements are stored for cubic case ResU.AnimCurveType.Cubic: //4 elements are stored for cubic
track.InterpolationType = InterpolationType.HERMITE; track.InterpolationType = InterpolationType.HERMITE;
var coef0 = animCurve.Offset + (animCurve.Keys[i, 0] * animCurve.Scale);
var coef1 = animCurve.Offset + (animCurve.Keys[i, 1] * animCurve.Scale);
var coef2 = animCurve.Offset + (animCurve.Keys[i, 2] * animCurve.Scale);
var coef3 = animCurve.Offset + (animCurve.Keys[i, 3] * animCurve.Scale);
var slopes = GetSlopes(animCurve, i);
track.Keys.Add(new Animation.KeyFrame() track.Keys.Add(new Animation.KeyFrame()
{ {
IsKeyed = true, IsKeyed = true,
InterType = InterpolationType.HERMITE, InterType = InterpolationType.HERMITE,
Frame = (int)animCurve.Frames[i], Frame = (int)animCurve.Frames[i],
Value = animCurve.Offset + (animCurve.Keys[i, 0] * animCurve.Scale), Value = coef0,
Slope1 = animCurve.Offset + (animCurve.Keys[i, 1] * animCurve.Scale), // Slope1 = slopes[0],
Slope2 = animCurve.Offset + (animCurve.Keys[i, 2] * animCurve.Scale), // Slope2 = slopes[1],
Delta = animCurve.Offset + (animCurve.Keys[i, 3] * animCurve.Scale),
}); });
break; break;
case ResU.AnimCurveType.Linear: //2 elements are stored for linear case ResU.AnimCurveType.Linear: //2 elements are stored for linear
@ -79,7 +84,6 @@ namespace Bfres.Structs
InterType = InterpolationType.STEP, InterType = InterpolationType.STEP,
Frame = (int)animCurve.Frames[i], Frame = (int)animCurve.Frames[i],
Value = (int)animCurve.Offset + (int)animCurve.Keys[i, 0] * animCurve.Scale, Value = (int)animCurve.Offset + (int)animCurve.Keys[i, 0] * animCurve.Scale,
Value1 = (int)animCurve.Offset + (int)animCurve.Keys[i, 0] * animCurve.Scale,
}); });
Console.WriteLine($"Frame {animCurve.Frames[i]} FrameINT {(int)animCurve.Frames[i]} Offset " + (int)animCurve.Offset + " " + ((int)animCurve.Offset + (int)animCurve.Keys[i, 0] * animCurve.Scale)); Console.WriteLine($"Frame {animCurve.Frames[i]} FrameINT {(int)animCurve.Frames[i]} Offset " + (int)animCurve.Offset + " " + ((int)animCurve.Offset + (int)animCurve.Keys[i, 0] * animCurve.Scale));
@ -92,6 +96,84 @@ namespace Bfres.Structs
return track; return track;
} }
public static float[] GetSlopes(AnimCurve curve, float index)
{
float[] slopes = new float[2];
if (curve.CurveType == AnimCurveType.Cubic)
{
float InSlope = 0;
float OutSlope = 0;
for (int i = 0; i < curve.Frames.Length; i++)
{
var coef0 = curve.Keys[i, 0] * curve.Scale + curve.Offset;
var coef1 = curve.Keys[i, 1] * curve.Scale + curve.Offset;
var coef2 = curve.Keys[i, 2] * curve.Scale + curve.Offset;
var coef3 = curve.Keys[i, 3] * curve.Scale + curve.Offset;
float time = 0;
float delta = 0;
if (i < curve.Frames.Length - 1)
{
var nextValue = curve.Keys[i + 1, 0] * curve.Scale + curve.Offset;
delta = nextValue - coef0;
time = curve.Frames[i + 1] - curve.Frames[i];
}
var slopeData = CurveInterpolationHelper.GetCubicSlopes(time, delta,
new float[4] { coef0, coef1, coef2, coef3, });
if (index == i)
{
OutSlope = slopeData[1];
return new float[2] { InSlope, OutSlope };
}
//The previous inslope is used
InSlope = slopeData[0];
}
}
return slopes;
}
public static float[] GetSlopes(ResU.AnimCurve curve, float index)
{
float[] slopes = new float[2];
if (curve.CurveType == ResU.AnimCurveType.Cubic)
{
float InSlope = 0;
float OutSlope = 0;
for (int i = 0; i < curve.Frames.Length; i++)
{
var coef0 = curve.Keys[i, 0] * curve.Scale + curve.Offset;
var coef1 = curve.Keys[i, 1] * curve.Scale + curve.Offset;
var coef2 = curve.Keys[i, 2] * curve.Scale + curve.Offset;
var coef3 = curve.Keys[i, 3] * curve.Scale + curve.Offset;
float time = 0;
float delta = 0;
if (i < curve.Frames.Length - 1)
{
var nextValue = curve.Keys[i + 1, 0] * curve.Scale + curve.Offset;
delta = nextValue - coef0;
time = curve.Frames[i + 1] - curve.Frames[i];
}
var slopeData = CurveInterpolationHelper.GetCubicSlopes(time, delta,
new float[4] { coef0, coef1, coef2, coef3, });
if (index == i)
{
OutSlope = slopeData[1];
return new float[2] { InSlope, OutSlope };
}
//The previous inslope is used
InSlope = slopeData[0];
}
}
return slopes;
}
public static BooleanKeyGroup CreateBooleanTrackWiiU(ResU.AnimCurve animCurve) public static BooleanKeyGroup CreateBooleanTrackWiiU(ResU.AnimCurve animCurve)
{ {
BooleanKeyGroup track = new BooleanKeyGroup(); BooleanKeyGroup track = new BooleanKeyGroup();
@ -176,17 +258,23 @@ namespace Bfres.Structs
{ {
case AnimCurveType.Cubic: //4 elements are stored for cubic case AnimCurveType.Cubic: //4 elements are stored for cubic
track.InterpolationType = InterpolationType.HERMITE; track.InterpolationType = InterpolationType.HERMITE;
var coef0 = animCurve.Offset + (animCurve.Keys[i, 0] * animCurve.Scale);
var coef1 = animCurve.Offset + (animCurve.Keys[i, 1] * animCurve.Scale);
var coef2 = animCurve.Offset + (animCurve.Keys[i, 2] * animCurve.Scale);
var coef3 = animCurve.Offset + (animCurve.Keys[i, 3] * animCurve.Scale);
var slopes = GetSlopes(animCurve, i);
var inSlope = slopes[0] * animCurve.Scale + animCurve.Offset;
var outSlope = slopes[1] * animCurve.Scale + animCurve.Offset;
track.Keys.Add(new Animation.KeyFrame() track.Keys.Add(new Animation.KeyFrame()
{ {
IsKeyed = true, IsKeyed = true,
InterType = InterpolationType.HERMITE, InterType = InterpolationType.HERMITE,
Frame = (int)animCurve.Frames[i], Frame = (int)animCurve.Frames[i],
Value = animCurve.Offset + (animCurve.Keys[i, 0] * animCurve.Scale), Value = coef0,
Slope1 = inSlope,
Value1 = animCurve.Offset + (animCurve.Keys[i, 0] * animCurve.Scale), Slope2 = outSlope,
Slope1 = animCurve.Offset + (animCurve.Keys[i, 1] * animCurve.Scale),
Slope2 = animCurve.Offset + (animCurve.Keys[i, 2] * animCurve.Scale),
Delta = animCurve.Offset + (animCurve.Keys[i, 3] * animCurve.Scale),
}); });
break; break;
case AnimCurveType.Linear: //2 elements are stored for linear case AnimCurveType.Linear: //2 elements are stored for linear

View File

@ -750,15 +750,6 @@ namespace Bfres.Structs
else else
shape.vertexAttributes = csvsettings.CreateNewAttributes(); shape.vertexAttributes = csvsettings.CreateNewAttributes();
shape.BoneIndex = 0;
shape.Text = obj.ObjectName;
shape.lodMeshes = obj.lodMeshes;
shape.CreateNewBoundingBoxes();
shape.CreateBoneList(obj, this, ForceSkinInfluence, ForceSkinInfluenceMax);
shape.CreateIndexList(obj, this);
shape.ApplyImportSettings(csvsettings, GetMaterial(shape.MaterialIndex));
shape.BoneIndices = shape.GetIndices(Skeleton);
Console.WriteLine($"ForceSkinInfluence {ForceSkinInfluence}"); Console.WriteLine($"ForceSkinInfluence {ForceSkinInfluence}");
if (!ForceSkinInfluence) if (!ForceSkinInfluence)
@ -768,6 +759,15 @@ namespace Bfres.Structs
Console.WriteLine($"VertexSkinCount { shape.VertexSkinCount}"); Console.WriteLine($"VertexSkinCount { shape.VertexSkinCount}");
shape.BoneIndex = 0;
shape.Text = obj.ObjectName;
shape.lodMeshes = obj.lodMeshes;
shape.CreateNewBoundingBoxes();
shape.CreateBoneList(obj, this, ForceSkinInfluence, ForceSkinInfluenceMax);
shape.CreateIndexList(obj, this);
shape.ApplyImportSettings(csvsettings, GetMaterial(shape.MaterialIndex));
shape.BoneIndices = shape.GetIndices(Skeleton);
if (shape.VertexSkinCount == 1) if (shape.VertexSkinCount == 1)
{ {
int boneIndex = shape.BoneIndices[0]; int boneIndex = shape.BoneIndices[0];
@ -1178,7 +1178,10 @@ namespace Bfres.Structs
else else
shape.vertexAttributes = settings.CreateNewAttributes(); shape.vertexAttributes = settings.CreateNewAttributes();
shape.BoneIndex = obj.BoneIndex; if (ForceSkinInfluence)
shape.VertexSkinCount = (byte)ForceSkinInfluenceMax;
else
shape.VertexSkinCount = obj.GetMaxSkinInfluenceCount();
if (obj.MaterialIndex + MatStartIndex < materials.Count && obj.MaterialIndex > 0) if (obj.MaterialIndex + MatStartIndex < materials.Count && obj.MaterialIndex > 0)
shape.MaterialIndex = obj.MaterialIndex + MatStartIndex; shape.MaterialIndex = obj.MaterialIndex + MatStartIndex;
@ -1192,10 +1195,9 @@ namespace Bfres.Structs
shape.ApplyImportSettings(settings, GetMaterial(shape.MaterialIndex)); shape.ApplyImportSettings(settings, GetMaterial(shape.MaterialIndex));
shape.BoneIndices = shape.GetIndices(Skeleton); shape.BoneIndices = shape.GetIndices(Skeleton);
if (ForceSkinInfluence) shape.OptmizeAttributeFormats();
shape.VertexSkinCount = (byte)ForceSkinInfluenceMax; shape.SaveShape(IsWiiU);
else shape.SaveVertexBuffer(IsWiiU);
shape.VertexSkinCount = obj.GetMaxSkinInfluenceCount();
if (shape.VertexSkinCount == 1 && shape.BoneIndices.Count > 0) if (shape.VertexSkinCount == 1 && shape.BoneIndices.Count > 0)
{ {
@ -1203,9 +1205,7 @@ namespace Bfres.Structs
shape.BoneIndex = boneIndex; shape.BoneIndex = boneIndex;
} }
shape.OptmizeAttributeFormats(); shape.BoneIndex = obj.BoneIndex;
shape.SaveShape(IsWiiU);
shape.SaveVertexBuffer(IsWiiU);
if (IsWiiU) if (IsWiiU)
{ {
@ -1316,12 +1316,19 @@ namespace Bfres.Structs
bn.FlagsTransformCumulative = BoneFlagsTransformCumulative.None; bn.FlagsTransformCumulative = BoneFlagsTransformCumulative.None;
bn.Name = bone.Text; bn.Name = bone.Text;
bn.RigidMatrixIndex = 0; bn.RigidMatrixIndex = 0;
bn.Rotation = new Syroot.Maths.Vector4F(bone.rotation[0], bn.Rotation = new Syroot.Maths.Vector4F(
bone.rotation[1], bone.rotation[2], bone.rotation[3]); bone.Rotation.X,
bn.Position = new Syroot.Maths.Vector3F(bone.position[0], bone.Rotation.Y,
bone.position[1], bone.position[2]); bone.Rotation.Z,
bn.Scale = new Syroot.Maths.Vector3F(bone.scale[0], bone.Rotation.W);
bone.scale[1], bone.scale[2]); bn.Position = new Syroot.Maths.Vector3F(
bone.Position.X,
bone.Position.Y,
bone.Position.Z);
bn.Scale = new Syroot.Maths.Vector3F(
bone.Scale.X,
bone.Scale.Y,
bone.Scale.Z);
bn.UserData = new List<UserData>(); bn.UserData = new List<UserData>();
bn.UserDataDict = new ResDict(); bn.UserDataDict = new ResDict();
} }

View File

@ -745,20 +745,19 @@ namespace Bfres.Structs
{ {
Text = genericBone.Text; Text = genericBone.Text;
position = new float[3]; Position = new OpenTK.Vector3(
rotation = new float[4]; genericBone.Position.X,
scale = new float[3]; genericBone.Position.Y,
genericBone.Position.Z);
EulerRotation = new OpenTK.Vector3(
genericBone.Rotation.X,
genericBone.Rotation.Y,
genericBone.Rotation.Z);
Scale = new OpenTK.Vector3(
genericBone.Scale.X,
genericBone.Scale.Y,
genericBone.Scale.Z);
position[0] = genericBone.position[0];
position[1] = genericBone.position[1];
position[2] = genericBone.position[2];
rotation[0] = genericBone.rotation[0];
rotation[1] = genericBone.rotation[1];
rotation[2] = genericBone.rotation[2];
rotation[3] = genericBone.rotation[3];
scale[0] = genericBone.scale[0];
scale[1] = genericBone.scale[1];
scale[2] = genericBone.scale[2];
RotationType = genericBone.RotationType; RotationType = genericBone.RotationType;
parentIndex = genericBone.parentIndex; parentIndex = genericBone.parentIndex;
RigidMatrixIndex = genericBone.RigidMatrixIndex; RigidMatrixIndex = genericBone.RigidMatrixIndex;
@ -769,9 +768,9 @@ namespace Bfres.Structs
{ {
if (BoneU != null) if (BoneU != null)
{ {
BoneU.Position = new Syroot.Maths.Vector3F(position[0], position[1], position[2]); BoneU.Position = new Syroot.Maths.Vector3F(Position.X, Position.Y, Position.Z);
BoneU.Scale = new Syroot.Maths.Vector3F(scale[0], scale[1], scale[2]); BoneU.Scale = new Syroot.Maths.Vector3F(Scale.X, Scale.Y, Scale.Z);
BoneU.Rotation = new Syroot.Maths.Vector4F(rotation[0], rotation[1], rotation[2], rotation[3]); BoneU.Rotation = new Syroot.Maths.Vector4F(Rotation.X, Rotation.Y, Rotation.Z, Rotation.W);
BoneU.Name = Text; BoneU.Name = Text;
BoneU.Flags = FlagVisible ? ResU.BoneFlags.Visible : 0; BoneU.Flags = FlagVisible ? ResU.BoneFlags.Visible : 0;
BoneU.ParentIndex = (short)parentIndex; BoneU.ParentIndex = (short)parentIndex;
@ -782,9 +781,9 @@ namespace Bfres.Structs
} }
else else
{ {
Bone.Position = new Syroot.Maths.Vector3F(position[0], position[1], position[2]); Bone.Position = new Syroot.Maths.Vector3F(Position.X, Position.Y, Position.Z);
Bone.Scale = new Syroot.Maths.Vector3F(scale[0], scale[1], scale[2]); Bone.Scale = new Syroot.Maths.Vector3F(Scale.X, Scale.Y, Scale.Z);
Bone.Rotation = new Syroot.Maths.Vector4F(rotation[0], rotation[1], rotation[2], rotation[3]); Bone.Rotation = new Syroot.Maths.Vector4F(Rotation.X, Rotation.Y, Rotation.Z, Rotation.W);
Bone.Name = Text; Bone.Name = Text;
Bone.Flags = FlagVisible ? BoneFlags.Visible : 0; Bone.Flags = FlagVisible ? BoneFlags.Visible : 0;
Bone.ParentIndex = (short)parentIndex; Bone.ParentIndex = (short)parentIndex;

View File

@ -576,23 +576,24 @@ namespace FirstPlugin
if (SetParent) if (SetParent)
bone.parentIndex = bn.ParentIndex; bone.parentIndex = bn.ParentIndex;
bone.scale = new float[3];
bone.rotation = new float[4];
bone.position = new float[3];
if (bn.FlagsRotation == BoneFlagsRotation.Quaternion) if (bn.FlagsRotation == BoneFlagsRotation.Quaternion)
bone.RotationType = STBone.BoneRotationType.Quaternion; bone.RotationType = STBone.BoneRotationType.Quaternion;
else else
bone.RotationType = STBone.BoneRotationType.Euler; bone.RotationType = STBone.BoneRotationType.Euler;
bone.scale[0] = bn.Scale.X;
bone.scale[1] = bn.Scale.Y; bone.Position = new OpenTK.Vector3(
bone.scale[2] = bn.Scale.Z; bn.Position.X,
bone.rotation[0] = bn.Rotation.X; bn.Position.Y,
bone.rotation[1] = bn.Rotation.Y; bn.Position.Z);
bone.rotation[2] = bn.Rotation.Z; bone.Rotation = new OpenTK.Quaternion(
bone.rotation[3] = bn.Rotation.W; bn.Rotation.X,
bone.position[0] = bn.Position.X; bn.Rotation.Y,
bone.position[1] = bn.Position.Y; bn.Rotation.Z,
bone.position[2] = bn.Position.Z; bn.Rotation.W);
bone.Scale = new OpenTK.Vector3(
bn.Scale.X,
bn.Scale.Y,
bn.Scale.Z);
} }
public static void SaveSkeleton(FSKL fskl, List<STBone> Bones) public static void SaveSkeleton(FSKL fskl, List<STBone> Bones)

View File

@ -380,26 +380,26 @@ namespace FirstPlugin
bone.BillboardIndex = bn.BillboardIndex; bone.BillboardIndex = bn.BillboardIndex;
bone.UseRigidMatrix = bn.RigidMatrixIndex != -1; bone.UseRigidMatrix = bn.RigidMatrixIndex != -1;
bone.UseSmoothMatrix = bn.SmoothMatrixIndex != -1; bone.UseSmoothMatrix = bn.SmoothMatrixIndex != -1;
if (SetParent) if (SetParent)
bone.parentIndex = bn.ParentIndex; bone.parentIndex = bn.ParentIndex;
bone.scale = new float[3];
bone.rotation = new float[4];
bone.position = new float[3];
if (bn.FlagsRotation == BoneFlagsRotation.Quaternion) if (bn.FlagsRotation == BoneFlagsRotation.Quaternion)
bone.RotationType = STBone.BoneRotationType.Quaternion; bone.RotationType = STBone.BoneRotationType.Quaternion;
else else
bone.RotationType = STBone.BoneRotationType.Euler; bone.RotationType = STBone.BoneRotationType.Euler;
bone.scale[0] = bn.Scale.X;
bone.scale[1] = bn.Scale.Y; bone.Position = new OpenTK.Vector3(
bone.scale[2] = bn.Scale.Z; bn.Position.X,
bone.rotation[0] = bn.Rotation.X; bn.Position.Y,
bone.rotation[1] = bn.Rotation.Y; bn.Position.Z);
bone.rotation[2] = bn.Rotation.Z; bone.Rotation = new OpenTK.Quaternion(
bone.rotation[3] = bn.Rotation.W; bn.Rotation.X,
bone.position[0] = bn.Position.X; bn.Rotation.Y,
bone.position[1] = bn.Position.Y; bn.Rotation.Z,
bone.position[2] = bn.Position.Z; bn.Rotation.W);
bone.Scale = new OpenTK.Vector3(
bn.Scale.X,
bn.Scale.Y,
bn.Scale.Z);
} }
public static void SetShape(this FSHP s, Shape shp) public static void SetShape(this FSHP s, Shape shp)

View File

@ -160,7 +160,6 @@ namespace FirstPlugin
{ {
if (bone.Parent == null) if (bone.Parent == null)
SkeletonFolder.Nodes.Add(bone); SkeletonFolder.Nodes.Add(bone);
} }
for (int i = 0; i < BMDFile.Shapes.Shapes.Count; i++) for (int i = 0; i < BMDFile.Shapes.Shapes.Count; i++)
@ -284,6 +283,10 @@ namespace FirstPlugin
{ {
int matIndex = node.Parent.Index; int matIndex = node.Parent.Index;
((BMDShapeWrapper)Meshes[node.Index]).SetMaterial((STGenericMaterial)MaterialFolder.Nodes[matIndex]); ((BMDShapeWrapper)Meshes[node.Index]).SetMaterial((STGenericMaterial)MaterialFolder.Nodes[matIndex]);
((BMDShapeWrapper)Meshes[node.Index]).Nodes.Add(MaterialFolder.Nodes[matIndex].Text);
Console.WriteLine("" + '"' + MaterialFolder.Nodes[matIndex].Text + '"' + ",");
} }
} }
} }
@ -291,6 +294,20 @@ namespace FirstPlugin
public void FillSkeleton(SuperBMDLib.BMD.INF1 INF1, STSkeleton skeleton, List<SuperBMDLib.Rigging.Bone> flatSkeleton) public void FillSkeleton(SuperBMDLib.BMD.INF1 INF1, STSkeleton skeleton, List<SuperBMDLib.Rigging.Bone> flatSkeleton)
{ {
for (int i = 1; i < INF1.FlatNodes.Count; i++)
{
SuperBMDLib.Scenegraph.SceneNode curNode = INF1.FlatNodes[i];
if (curNode.Type == SuperBMDLib.Scenegraph.Enums.NodeType.Joint)
{
var Bone = flatSkeleton[curNode.Index];
var stBone = new STBone(skeleton);
stBone.Text = Bone.Name;
stBone.FromTransform(Bone.TransformationMatrix);
skeleton.bones.Add(stBone);
}
}
int boneIndex = 0;
for (int i = 1; i < INF1.FlatNodes.Count; i++) for (int i = 1; i < INF1.FlatNodes.Count; i++)
{ {
SuperBMDLib.Scenegraph.SceneNode curNode = INF1.FlatNodes[i]; SuperBMDLib.Scenegraph.SceneNode curNode = INF1.FlatNodes[i];
@ -299,16 +316,18 @@ namespace FirstPlugin
{ {
var Bone = flatSkeleton[curNode.Index]; var Bone = flatSkeleton[curNode.Index];
var stBone = new STBone(skeleton); var stBone = skeleton.bones[boneIndex];
stBone.Text = Bone.Name; if (curNode.Parent != null && curNode.Parent.Type == SuperBMDLib.Scenegraph.Enums.NodeType.Joint) {
stBone.FromTransform(Bone.TransformationMatrix); var parent = flatSkeleton[curNode.Parent.Index];
if (Bone.Parent != null) var boneParent = skeleton.GetBone(parent.Name);
stBone.parentIndex = flatSkeleton.IndexOf(Bone.Parent); if (boneParent != null)
stBone.parentIndex = skeleton.bones.IndexOf(boneParent);
}
else else
stBone.parentIndex = -1; stBone.parentIndex = -1;
skeleton.bones.Add(stBone); boneIndex++;
} }
} }
} }

View File

@ -26,24 +26,25 @@ namespace FirstPlugin
public static string ToYaml(ByamlExt.Byaml.BymlFileData data) public static string ToYaml(ByamlExt.Byaml.BymlFileData data)
{ {
/* var settings = new SerializerSettings() var settings = new SerializerSettings()
{ {
EmitTags = false, EmitTags = false,
EmitAlias = false, EmitAlias = false,
DefaultStyle = SharpYaml.YamlStyle.Flow, DefaultStyle = SharpYaml.YamlStyle.Flow,
SortKeyForMapping = false, SortKeyForMapping = false,
EmitShortTypeName = true, EmitShortTypeName = true,
EmitCapacityForList = false, EmitCapacityForList = false,
LimitPrimitiveFlowSequence = 4, LimitPrimitiveFlowSequence = 4,
}; };
settings.RegisterTagMapping("!u", typeof(uint)); settings.RegisterTagMapping("!u", typeof(uint));
settings.RegisterTagMapping("!l", typeof(int)); settings.RegisterTagMapping("!l", typeof(int));
settings.RegisterTagMapping("!d", typeof(double)); settings.RegisterTagMapping("!d", typeof(double));
settings.RegisterTagMapping("!ul", typeof(ulong)); settings.RegisterTagMapping("!ul", typeof(ulong));
settings.RegisterTagMapping("!ll", typeof(long)); settings.RegisterTagMapping("!ll", typeof(long));
var serializer = new Serializer(settings);*/ var serializer = new Serializer(settings);
return serializer.Serialize(data);
NodePaths.Clear(); NodePaths.Clear();
refNodeId = 0; refNodeId = 0;
@ -256,7 +257,8 @@ namespace FirstPlugin
private static string ConvertValue(dynamic node) private static string ConvertValue(dynamic node)
{ {
if (node is bool) return ((bool)node)? "true" : "false"; if (node is bool) return ((bool)node) ? "true" : "false";
else if (node is float) return string.Format("{0:0.000.00}", node);
else return node.ToString(); else return node.ToString();
} }
} }

View File

@ -1,162 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using Toolbox;
using System.Windows.Forms;
using Toolbox.Library;
using Toolbox.Library.IO;
using Toolbox.Library.Forms;
namespace FirstPlugin
{
public class BFOTF : TreeNodeFile, IFileFormat, IContextMenuNode
{
public FileType FileType { get; set; } = FileType.Font;
public bool CanSave { get; set; }
public string[] Description { get; set; } = new string[] { "Binary Cafe Open Type Font" };
public string[] Extension { get; set; } = new string[] { "*.bfotf" };
public string FileName { get; set; }
public string FilePath { get; set; }
public IFileInfo IFileInfo { get; set; }
public bool Identify(System.IO.Stream stream)
{
using (var reader = new Toolbox.Library.IO.FileReader(stream, true))
{
uint magic = reader.ReadUInt32();
reader.Position = 0;
return magic == 0x1A879BD9 || magic == 0x1E1AF836 || magic == 0xC1DE68F3;
}
}
public Type[] Types
{
get
{
List<Type> types = new List<Type>();
return types.ToArray();
}
}
[DllImport("gdi32.dll")]
private static extern IntPtr AddFontMemResourceEx(IntPtr pbFont, uint cbFont, IntPtr pdv, [In] ref uint pcFonts);
public byte[] DecryptedFont { get; set; }
//Decryption process from https://github.com/TheFearsomeDzeraora/BFTTFutil/blob/master/Program.cs
public void Load(System.IO.Stream stream)
{
Text = FileName;
using (var reader = new FileReader(stream))
{
uint decryptionKey = 0;
uint magic = reader.ReadUInt32();
switch (magic)
{
case 0x1A879BD9: decryptionKey = 2785117442U; break;
case 0x1E1AF836: decryptionKey = 1231165446U; break;
case 0xC1DE68F3: decryptionKey = 2364726489U; break;
default:
Console.WriteLine("Err 0x2: Input file isn't a BFTTF\\BFOTF");
break;
}
byte[] inFile = reader.getSection(0, (int)reader.BaseStream.Length);
if (inFile.Length <= 8) return;
uint value = GetUInt32(inFile, 4) ^ decryptionKey;
if (inFile.Length < value) return;
byte[] outFile = new byte[inFile.Length - 8];
int pos = 8;
while (pos < inFile.Length)
{
SetToUInt32(GetUInt32(inFile, pos) ^ decryptionKey, outFile, pos - 8);
pos += 4;
}
DecryptedFont = outFile;
}
}
public ToolStripItem[] GetContextMenuItems()
{
List<ToolStripItem> Items = new List<ToolStripItem>();
Items.Add(new STToolStipMenuItem("Export", null, ExportAction, Keys.Control | Keys.E));
return Items.ToArray();
}
private void ExportAction(object sender, EventArgs args)
{
SaveFileDialog sfd = new SaveFileDialog();
sfd.FileName = Text;
sfd.DefaultExt = System.IO.Path.GetExtension(Text);
sfd.Filter = "Open Type Font |*.otf;";
if (sfd.ShowDialog() == DialogResult.OK)
{
System.IO.File.WriteAllBytes(sfd.FileName, DecryptedFont);
}
}
public System.Drawing.Font ToFont(float Size = 72)
{
System.Drawing.Text.PrivateFontCollection privateFonts = new System.Drawing.Text.PrivateFontCollection();
// We HAVE to do this to register the font to the system (Weird .NET bug !)
var fontDataPtr = Marshal.AllocCoTaskMem(DecryptedFont.Length);
Marshal.Copy(DecryptedFont, 0, fontDataPtr, DecryptedFont.Length);
uint cFonts = 0;
AddFontMemResourceEx(fontDataPtr, (uint)DecryptedFont.Length, IntPtr.Zero, ref cFonts);
privateFonts.AddMemoryFont(fontDataPtr, DecryptedFont.Length);
return new System.Drawing.Font(privateFonts.Families[0], Size);
}
public override void OnClick(TreeView treeview)
{
var font = ToFont();
var texbox = new RichTextBox() { Multiline = true, BorderStyle = BorderStyle.None, Dock = DockStyle.Fill };
texbox.BackColor = FormThemes.BaseTheme.FormBackColor;
texbox.ForeColor = FormThemes.BaseTheme.FormForeColor;
UserControl editor = new UserControl();
editor.Controls.Add(texbox);
LibraryGUI.LoadEditor(editor);
editor.Text = Text;
editor.Dock = DockStyle.Fill;
editor.Font = font;
texbox.Text = "Preview Text!";
}
private static UInt32 GetUInt32(byte[] data, int pos)
{
return (UInt32)(data[pos + 3] | data[pos + 2] << 8 | data[pos + 1] << 16 | data[pos] << 24);
}
private static void SetToUInt32(uint val, byte[] data, int pos)
{
data[pos + 3] = (byte)(val & (uint)byte.MaxValue);
data[pos + 2] = (byte)(val >> 8 & (uint)byte.MaxValue);
data[pos + 1] = (byte)(val >> 16 & (uint)byte.MaxValue);
data[pos] = (byte)(val >> 24 & (uint)byte.MaxValue);
}
public void Unload()
{
DecryptedFont = null;
GC.WaitForPendingFinalizers();
}
public void Save(System.IO.Stream stream)
{
}
}
}

View File

@ -17,7 +17,7 @@ namespace FirstPlugin
public bool CanSave { get; set; } public bool CanSave { get; set; }
public string[] Description { get; set; } = new string[] { "Binary Cafe True Type Font" }; public string[] Description { get; set; } = new string[] { "Binary Cafe True Type Font" };
public string[] Extension { get; set; } = new string[] { "*.bfttf" }; public string[] Extension { get; set; } = new string[] { "*.bfttf", "*.bfotf" };
public string FileName { get; set; } public string FileName { get; set; }
public string FilePath { get; set; } public string FilePath { get; set; }
public IFileInfo IFileInfo { get; set; } public IFileInfo IFileInfo { get; set; }

View File

@ -174,30 +174,31 @@ namespace FirstPlugin
if (HasSkeleton) if (HasSkeleton)
{ {
foreach (var bone in header.SectionData.SkeletonChunk.Bones) var bonesOrdered = header.SectionData.SkeletonChunk.Bones.OrderBy(x => x.ID).ToList();
foreach (var bone in bonesOrdered)
{ {
STBone genericBone = new STBone(Skeleton); STBone genericBone = new STBone(Skeleton);
genericBone.parentIndex = bone.ParentIndex; genericBone.parentIndex = bone.ParentIndex;
genericBone.position = new float[3];
genericBone.scale = new float[3];
genericBone.rotation = new float[4];
genericBone.Checked = true; genericBone.Checked = true;
genericBone.Text = $"Bone {bone.ID}"; genericBone.Text = $"Bone {bone.ID}";
genericBone.RotationType = STBone.BoneRotationType.Euler; genericBone.RotationType = STBone.BoneRotationType.Euler;
genericBone.position[0] = bone.Translation.X; genericBone.Position = new OpenTK.Vector3(
genericBone.position[1] = bone.Translation.Y; bone.Translation.X,
genericBone.position[2] = bone.Translation.Z; bone.Translation.Y,
bone.Translation.Z
genericBone.scale[0] = bone.Scale.X; );
genericBone.scale[1] = bone.Scale.Y; genericBone.EulerRotation = new OpenTK.Vector3(
genericBone.scale[2] = bone.Scale.Z; bone.Rotation.X,
bone.Rotation.Y,
genericBone.rotation[0] = bone.Rotation.X; bone.Rotation.Z
genericBone.rotation[1] = bone.Rotation.Y; );
genericBone.rotation[2] = bone.Rotation.Z; genericBone.Scale = new OpenTK.Vector3(
bone.Scale.X,
bone.Scale.Y,
bone.Scale.Z
);
Skeleton.bones.Add(genericBone); Skeleton.bones.Add(genericBone);
} }
@ -289,8 +290,11 @@ namespace FirstPlugin
List<ushort> SkinnedBoneTable = new List<ushort>(); List<ushort> SkinnedBoneTable = new List<ushort>();
foreach (var prim in shape.Primatives) foreach (var prim in shape.Primatives)
{ {
if (prim.BoneIndexTable != null) if (prim.BoneIndexTable != null) {
SkinnedBoneTable.AddRange(prim.BoneIndexTable); SkinnedBoneTable.AddRange(prim.BoneIndexTable);
foreach (var bone in prim.BoneIndexTable)
Console.WriteLine($"{genericMesh.Text} SkeletonB {Skeleton.bones[(int)bone].Text} index {bone}");
}
} }
//Now load the vertex and face data //Now load the vertex and face data
@ -363,12 +367,11 @@ namespace FirstPlugin
var BoneIndices = shape.BoneIndices.VertexData[v]; var BoneIndices = shape.BoneIndices.VertexData[v];
for (int j = 0; j < shape.boneDimension; j++) for (int j = 0; j < shape.boneDimension; j++)
{ {
if (BoneIndices[j] < SkinnedBoneTable.Count) if (BoneIndices[j] < SkinnedBoneTable.Count)
vert.boneIds.Add((int)SkinnedBoneTable[(int)BoneIndices[j]]); vert.boneIds.Add((int)SkinnedBoneTable[(int)BoneIndices[j]]);
// Console.WriteLine("boneIds " + BoneIndices[j]); // Console.WriteLine("boneIds " + BoneIndices[j]);
// ushort index = shape.Primatives[0].BoneIndexTable[(uint)BoneIndices[j]]; // ushort index = shape.Primatives[0].BoneIndexTable[(uint)BoneIndices[j]];
// vert.boneIds.Add((int)BoneIndices[j]);
} }
} }
if (shape.BoneWeights.VertexData != null && HasWeights && shape.BoneWeights.VertexData.Length > v) if (shape.BoneWeights.VertexData != null && HasWeights && shape.BoneWeights.VertexData.Length > v)
@ -376,7 +379,6 @@ namespace FirstPlugin
var BoneWeights = shape.BoneWeights.VertexData[v]; var BoneWeights = shape.BoneWeights.VertexData[v];
for (int j = 0; j < shape.boneDimension; j++) for (int j = 0; j < shape.boneDimension; j++)
{ {
Console.WriteLine("weight " + BoneWeights[j]);
vert.boneWeights.Add(BoneWeights[j]); vert.boneWeights.Add(BoneWeights[j]);
} }
} }

View File

@ -148,9 +148,9 @@ namespace FirstPlugin
if (node.RotationX.HasKeys || node.RotationY.HasKeys || node.RotationZ.HasKeys) if (node.RotationX.HasKeys || node.RotationY.HasKeys || node.RotationZ.HasKeys)
{ {
float x = node.RotationX.HasKeys ? node.RotationX.GetFrameValue(Frame) : b.rotation[0]; float x = node.RotationX.HasKeys ? node.RotationX.GetFrameValue(Frame) : b.EulerRotation.X;
float y = node.RotationY.HasKeys ? node.RotationY.GetFrameValue(Frame) : b.rotation[1]; float y = node.RotationY.HasKeys ? node.RotationY.GetFrameValue(Frame) : b.EulerRotation.Y;
float z = node.RotationZ.HasKeys ? node.RotationZ.GetFrameValue(Frame) : b.rotation[2]; float z = node.RotationZ.HasKeys ? node.RotationZ.GetFrameValue(Frame) : b.EulerRotation.Z;
b.rot = EulerToQuat(z, y, x); b.rot = EulerToQuat(z, y, x);
} }
} }

View File

@ -7,7 +7,9 @@ using Toolbox;
using System.Windows.Forms; using System.Windows.Forms;
using Toolbox.Library; using Toolbox.Library;
using Toolbox.Library.IO; using Toolbox.Library.IO;
using HyruleWarriors.G1M; using Toolbox.Library.Forms;
using Toolbox.Library.Rendering;
using OpenTK;
namespace HyruleWarriors.G1M namespace HyruleWarriors.G1M
{ {
@ -39,6 +41,54 @@ namespace HyruleWarriors.G1M
} }
} }
//Check for the viewport in the object editor
//This is attached to it to load multiple file formats within the object editor to the viewer
Viewport viewport
{
get
{
var editor = LibraryGUI.GetObjectEditor();
return editor.GetViewport();
}
set
{
var editor = LibraryGUI.GetObjectEditor();
editor.LoadViewport(value);
}
}
bool DrawablesLoaded = false;
public override void OnClick(TreeView treeView)
{
//Make sure opengl is enabled
if (Runtime.UseOpenGL)
{
//Open the viewport
if (viewport == null)
{
viewport = new Viewport(ObjectEditor.GetDrawableContainers());
viewport.Dock = DockStyle.Fill;
}
//Make sure to load the drawables only once so set it to true!
if (!DrawablesLoaded)
{
ObjectEditor.AddContainer(DrawableContainer);
DrawablesLoaded = true;
}
//Reload which drawable to display
viewport.ReloadDrawables(DrawableContainer);
LibraryGUI.LoadEditor(viewport);
viewport.Text = Text;
}
}
public G1M_Renderer Renderer;
public DrawableContainer DrawableContainer = new DrawableContainer();
public void Load(System.IO.Stream stream) public void Load(System.IO.Stream stream)
{ {
Read(new FileReader(stream)); Read(new FileReader(stream));
@ -54,9 +104,20 @@ namespace HyruleWarriors.G1M
} }
public G1MS Skeleton { get; set; } public G1MS Skeleton { get; set; }
public G1MG Model { get; set; }
public NUNO NUNO { get; set; }
public NUNV NUNV { get; set; }
TreeNode meshNode;
public void Read(FileReader reader) public void Read(FileReader reader)
{ {
Renderer = new G1M_Renderer();
Renderer.G1MFile = this;
DrawableContainer = new DrawableContainer();
DrawableContainer.Name = FileName;
DrawableContainer.Drawables.Add(Renderer);
reader.ByteOrder = Syroot.BinaryData.ByteOrder.BigEndian; reader.ByteOrder = Syroot.BinaryData.ByteOrder.BigEndian;
string Magic = reader.ReadString(4); string Magic = reader.ReadString(4);
@ -84,52 +145,86 @@ namespace HyruleWarriors.G1M
for (int i = 0; i < numChunks; i++) for (int i = 0; i < numChunks; i++)
{ {
G1MChunkCommon chunk = new G1MChunkCommon(); G1MChunkCommon chunk = new G1MChunkCommon();
long chunkPosition = reader.Position; chunk.ChunkPosition = reader.Position;
string chunkMagic = reader.ReadString(4, Encoding.ASCII); chunk.Magic = reader.ReadString(4, Encoding.ASCII);
uint chunkVersion = reader.ReadUInt32(); chunk.ChunkVersion = reader.ReadUInt32();
uint chunkSize = reader.ReadUInt32(); chunk.ChunkSize = reader.ReadUInt32();
if (chunkMagic == "G1MF") Console.WriteLine("chunkMagic " + chunk.Magic);
if (chunk.Magic == "G1MF")
{ {
} }
else if (chunkMagic == "SM1G") else if (chunk.Magic == "SM1G" || chunk.Magic == "G1MS")
{ {
Skeleton = new G1MS(reader); Skeleton = new G1MS(reader);
Renderer.Skeleton = Skeleton.GenericSkeleton;
DrawableContainer.Drawables.Add(Skeleton.GenericSkeleton);
TreeNode skeleton = new TreeNode("Skeleton");
Nodes.Add(skeleton);
foreach (var bn in Skeleton.GenericSkeleton.bones)
if (bn.Parent == null)
{
skeleton.Nodes.Add(bn);
}
} }
else if (chunkMagic == "G1MS") else if (chunk.Magic == "G1MM")
{ {
} }
else if (chunkMagic == "G1MM") else if (chunk.Magic == "G1MG")
{
Model = new G1MG(reader);
Renderer.Meshes.AddRange(Model.GenericMeshes);
meshNode = new TreeNode("Meshes");
Nodes.Add(meshNode);
foreach (var mesh in Model.GenericMeshes)
meshNode.Nodes.Add(mesh);
if (Skeleton != null)
{
foreach (var mesh in Model.GenericMeshes)
{
bool isSingleBind = false;;
if (isSingleBind)
{
for (int v = 0; v < mesh.vertices.Count; v++)
{
var boneId = mesh.vertices[v].boneIds[0];
var transform = Skeleton.GenericSkeleton.bones[boneId].Transform;
mesh.vertices[v].pos = Vector3.TransformPosition(
mesh.vertices[v].pos, transform);
mesh.vertices[v].nrm = Vector3.TransformNormal(
mesh.vertices[v].nrm, transform);
}
}
}
}
}
else if (chunk.Magic == "COLL")
{ {
} }
else if (chunkMagic == "G1MG") else if (chunk.Magic == "HAIR")
{ {
} }
else if (chunkMagic == "COLL") else if (chunk.Magic == "NUNO")
{
NUNO = new NUNO(reader, chunk.ChunkVersion);
}
else if (chunk.Magic == "NUNS")
{ {
} }
else if (chunkMagic == "HAIR") else if (chunk.Magic == "NUNV")
{ {
NUNV = new NUNV(reader, chunk.ChunkVersion);
} }
else if (chunkMagic == "NUNO") else if (chunk.Magic == "EXTR")
{
}
else if (chunkMagic == "NUNS")
{
}
else if (chunkMagic == "NUNV")
{
}
else if (chunkMagic == "EXTR")
{ {
} }
@ -137,11 +232,138 @@ namespace HyruleWarriors.G1M
{ {
} }
reader.SeekBegin(chunk.ChunkPosition + chunk.ChunkSize); reader.SeekBegin(chunk.ChunkPosition + chunk.ChunkSize);
} }
ComputeClothDrivers();
SetLevelOfDetailGroups();
}
/// <summary>
/// Computes mesh and bone cloth drivers
/// </summary>
public void ComputeClothDrivers()
{
var boneList = Skeleton.GenericSkeleton.bones;
var nunProps = new List<NUNO.NUNOType0303Struct>();
uint nunoOffset = 0;
if (NUNO != null)
{
nunoOffset = (uint)NUNO.NUNO0303StructList.Count;
foreach (var nuno0303 in NUNO.NUNO0303StructList)
nunProps.Add(nuno0303);
}
if (NUNV != null) {
foreach (var nuno0303 in NUNV.NUNV0303StructList)
nunProps.Add(nuno0303);
}
foreach (var prop in nunProps)
{
int boneStart = boneList.Count;
var parentBone = Model.JointInfos[prop.BoneParentID - 1].JointIndices[0];
GenericRenderedObject mesh = new GenericRenderedObject();
mesh.Text = $"driver_{boneList.Count}";
mesh.Checked = true;
Renderer.Meshes.Add(mesh);
meshNode.Nodes.Add(mesh);
var polyGroup = new STGenericPolygonGroup();
polyGroup.Material = new STGenericMaterial();
polyGroup.Material.Text = "driver_cloth";
polyGroup.PrimativeType = STPrimitiveType.Triangles;
mesh.PolygonGroups.Add(polyGroup);
for (int p = 0; p < prop.Points.Length; p++) {
var point = prop.Points[p];
var link = prop.Influences[p];
STBone b = new STBone(Skeleton.GenericSkeleton);
b.Text = $"CP_{boneList.Count}";
b.FromTransform(OpenTK.Matrix4.Identity);
b.Position = point.Xyz;
b.parentIndex = link.P3;
if (b.parentIndex == -1)
b.parentIndex = (int)parentBone;
else
{
b.parentIndex += boneStart;
b.Position = OpenTK.Vector3.TransformPosition(
point.Xyz, Skeleton.GenericSkeleton.GetBoneTransform((int)parentBone) *
Skeleton.GenericSkeleton.GetBoneTransform(b.parentIndex).Inverted());
}
boneList.Add(b);
Skeleton.GenericSkeleton.reset();
Skeleton.GenericSkeleton.update();
mesh.vertices.Add(new Vertex()
{
pos = Vector3.TransformPosition(Vector3.Zero,
Skeleton.GenericSkeleton.GetBoneTransform(boneList.Count - 1)),
boneWeights = new List<float>() { 1 },
boneIds = new List<int>() { boneList.Count - 1 },
});
if (link.P1 > 0 && link.P3 > 0)
{
polyGroup.faces.Add(p);
polyGroup.faces.Add(link.P1);
polyGroup.faces.Add(link.P3);
}
if (link.P2 > 0 && link.P4 > 0)
{
polyGroup.faces.Add(p);
polyGroup.faces.Add(link.P2);
polyGroup.faces.Add(link.P4);
}
}
mesh.CalculateNormals();
}
}
private void SetLevelOfDetailGroups()
{
foreach (var group in Model.LodGroups[0].Meshes)
{
var isCloth = (group.ID & 0xF) == 1;
var isPoint = (group.ID & 0xF) == 2;
var NunoSection = (group.ID2 - (group.ID2 % 10000)) / 10000;
foreach (var polyindex in group.Indices)
{
if (polyindex > Model.SubMeshInfos.Length)
continue;
var poly = Model.SubMeshInfos[polyindex];
var mesh = Model.GenericMeshes[(int)polyindex];
mesh.Text = $"{group.Name}_" + (isPoint ? "point" : "") + (isCloth ? "cloth" : "") + $"_{polyindex}";
mesh.Text = mesh.Text.Replace(@"\p{C}+", string.Empty);
if (isPoint)
{
for (int i = 0; i < mesh.vertices.Count; i++)
{
var vert = mesh.vertices[i];
vert.pos = Vector3.TransformPosition(vert.pos,
Skeleton.GenericSkeleton.GetBoneTransform((int)Model.JointInfos[poly.IndexIntoJointMap].JointIndices[0]));
vert.nrm = Vector3.TransformNormal(vert.nrm,
Skeleton.GenericSkeleton.GetBoneTransform((int)Model.JointInfos[poly.IndexIntoJointMap].JointIndices[0]));
mesh.vertices[i] = vert;
}
}
if (isCloth)
{
}
}
}
} }
} }
} }

View File

@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Toolbox.Library.IO;
namespace HyruleWarriors.G1M
{
public interface IChunk
{
void Read(FileReader reader);
void Write(FileWriter reader);
}
public class G1MCommon
{
public static T[] ParseStructArray<T>(FileReader reader) {
int count = reader.ReadInt32();
return reader.ReadMultipleStructs<T>(count).ToArray();
}
public static T[] ParseArray<T>(FileReader reader)
where T : IChunk, new()
{
int count = reader.ReadInt32();
T[] values = new T[count];
for (int i = 0; i < count; i++)
{
values[i] = new T();
values[i].Read(reader);
}
return values;
}
}
}

View File

@ -6,7 +6,7 @@ using System.Threading.Tasks;
namespace HyruleWarriors.G1M namespace HyruleWarriors.G1M
{ {
public enum VertexAttriubte public enum VertexAttriubte : byte
{ {
Position, Position,
Weights, Weights,
@ -19,4 +19,11 @@ namespace HyruleWarriors.G1M
Color = 0x0A, Color = 0x0A,
Fog = 0x0B, Fog = 0x0B,
} }
public enum FaceType : uint
{
Byte = 0x8,
UInt16 = 0x10,
UInt32 = 0x20,
}
} }

View File

@ -5,6 +5,9 @@ using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Toolbox.Library.IO; using Toolbox.Library.IO;
using Toolbox.Library; using Toolbox.Library;
using Toolbox.Library.Rendering;
using OpenTK;
using System.Runtime.InteropServices;
namespace HyruleWarriors.G1M namespace HyruleWarriors.G1M
{ {
@ -12,15 +15,637 @@ namespace HyruleWarriors.G1M
{ {
private string Type { get; set; } private string Type { get; set; }
public BoundingBox BoundingBox;
public Material[] Materials { get; set; }
public ShaderData[] Shaders { get; set; }
public VertexBuffer[] VertexBuffers { get; set; }
public VertexAttributeList[] Attributes { get; set; }
public JointMapInfo[] JointInfos { get; set; }
public IndexBuffer[] IndexBuffers { get; set; }
public SubMeshInfo[] SubMeshInfos { get; set; }
public LodGroup[] LodGroups { get; set; }
public List<GenericRenderedObject> GenericMeshes = new List<GenericRenderedObject>();
public G1MG(FileReader reader) public G1MG(FileReader reader)
{ {
Type = reader.ReadString(3, Encoding.ASCII); Type = reader.ReadString(3, Encoding.ASCII);
reader.ReadByte();//padding reader.ReadByte();//padding
reader.ReadSingle(); //unk
if (Type == "DX1" || Type == "NX_") BoundingBox = new BoundingBox()
{ {
Min = reader.ReadVec3(),
Max = reader.ReadVec3(),
};
uint numChunks = reader.ReadUInt32();
for (int i = 0; i < numChunks; i++)
{
long pos = reader.Position;
uint chunkMagic = reader.ReadUInt32();
uint chunkSize = reader.ReadUInt32();
switch (chunkMagic)
{
case 0x00010001: //Unknown
break;
case 0x00010002: //Materials
Materials = G1MCommon.ParseArray<Material>(reader);
break;
case 0x00010003: //Shaders
Shaders = G1MCommon.ParseArray<ShaderData>(reader);
break;
case 0x00010004: //Vertex Buffer
VertexBuffers = G1MCommon.ParseArray<VertexBuffer>(reader);
break;
case 0x00010005: //Specs
Attributes = G1MCommon.ParseArray<VertexAttributeList>(reader);
break;
case 0x00010006: //Joint map info
JointInfos = G1MCommon.ParseArray<JointMapInfo>(reader);
break;
case 0x00010007: //Index buffer
IndexBuffers = G1MCommon.ParseArray<IndexBuffer>(reader);
break;
case 0x00010008: //Sub mesh info
SubMeshInfos = G1MCommon.ParseArray<SubMeshInfo>(reader);
break;
case 0x00010009: //Level of detail info
LodGroups = G1MCommon.ParseArray<LodGroup>(reader);
break;
default:
Console.WriteLine("Unknown chunk! " + chunkMagic.ToString());
break;
}
reader.SeekBegin(pos + chunkSize);
}
ToGenericMeshes(reader.IsBigEndian);
}
private void ToGenericMeshes(bool isBigEndian)
{
foreach (SubMeshInfo meshInfo in SubMeshInfos) {
GenericRenderedObject genericMesh = new GenericRenderedObject();
genericMesh.Text = $"Mesh_{GenericMeshes.Count}";
GenericMeshes.Add(genericMesh);
STGenericPolygonGroup polyGroup = new STGenericPolygonGroup();
genericMesh.PolygonGroups.Add(polyGroup);
var mat = Materials[(int)meshInfo.TextureID];
mat.Diffuse.TextureIndex = mat.TextureIndices[0][0];
polyGroup.Material = mat;
Console.WriteLine($"TextureID {meshInfo.TextureID}");
Console.WriteLine($"MaterialID {meshInfo.MaterialID}");
//Set face type
if (meshInfo.IndexBufferFormat == 3)
polyGroup.PrimativeType = STPrimitiveType.Triangles;
else if (meshInfo.IndexBufferFormat == 4)
polyGroup.PrimativeType = STPrimitiveType.TrangleStrips;
//Get faces
var buffer = IndexBuffers[(int)meshInfo.IndexBufferID];
var indcies = buffer.GetIndices(isBigEndian,
meshInfo.IndexBufferOffset,
meshInfo.IndexBufferCount).ToArray();
for (int f = 0; f < indcies.Length; f++)
polyGroup.faces.Add((int)indcies[f]);
//Get vertices
genericMesh.vertices.AddRange(GetVertices((int)meshInfo.VertexBufferID,
(int)meshInfo.IndexIntoJointMap, meshInfo.VertexBufferOffset, isBigEndian));
}
}
public List<Vertex> GetVertices(int index, int jointMapIndex, uint offset, bool isBigEndian)
{
var buffer = VertexBuffers[index];
var attributeList = Attributes[index];
List<Vertex> vertices = new List<Vertex>();
var skinningList = JointInfos[jointMapIndex];
using (var dataReader = new FileReader(buffer.BufferData))
{
dataReader.SetByteOrder(isBigEndian);
dataReader.SeekBegin(offset);
for (int i = 0; i < buffer.ElementCount; i++)
{
Vertex vertex = new Vertex();
vertices.Add(vertex);
foreach (var att in attributeList.Attributes)
{
dataReader.SeekBegin((uint)(i * buffer.Stride + att.Offset));
switch (att.AttributeType)
{
case VertexAttriubte.Position:
if (att.DataType == 0x02 || att.DataType == 0x03 ||
att.DataType == 0x0200 || att.DataType == 0x0300)
{
vertex.pos = new Vector3(
dataReader.ReadSingle(),
dataReader.ReadSingle(),
dataReader.ReadSingle());
dataReader.ReadSingle(); //extra
}
else if (att.DataType == 0x000B || att.DataType == 0x000B)
{
vertex.pos = new Vector3(
dataReader.ReadHalfSingle(),
dataReader.ReadHalfSingle(),
dataReader.ReadHalfSingle());
dataReader.ReadHalfSingle(); //extra
}
break;
case VertexAttriubte.Normals:
if (att.DataType == 0x000B || att.DataType == 0x000B)
{
vertex.nrm = new Vector3(
dataReader.ReadHalfSingle(),
dataReader.ReadHalfSingle(),
dataReader.ReadHalfSingle());
dataReader.ReadHalfSingle(); //extra
}
else if (att.DataType == 0x02 || att.DataType == 0x03 ||
att.DataType == 0x0200 || att.DataType == 0x0300)
{
vertex.nrm = new Vector3(
dataReader.ReadSingle(),
dataReader.ReadSingle(),
dataReader.ReadSingle());
dataReader.ReadSingle(); //extra
}
break;
case VertexAttriubte.TexCoord0:
if (att.DataType == 0x0001 || att.DataType == 0x0100)
{
vertex.uv0 = new Vector2(
dataReader.ReadSingle(),
dataReader.ReadSingle());
}
else if (att.DataType == 0x000A || att.DataType == 0x0A00)
{
vertex.uv0 = new Vector2(
dataReader.ReadHalfSingle(),
dataReader.ReadHalfSingle());
}
break;
case VertexAttriubte.Color:
if (att.Layer == 0)
{
if (att.DataType == 0x0200 || att.DataType == 0x0300)
{
vertex.col = new Vector4(
dataReader.ReadHalfSingle(),
dataReader.ReadHalfSingle(),
dataReader.ReadHalfSingle(),
1.0f);
}
else if (att.DataType == 0x0003 || att.DataType == 0x0300)
{
vertex.col = new Vector4(
dataReader.ReadSingle(),
dataReader.ReadSingle(),
dataReader.ReadSingle(),
dataReader.ReadSingle());
}
else if (att.DataType == 0x000B || att.DataType == 0x0B00)
{
vertex.col = new Vector4(
dataReader.ReadHalfSingle(),
dataReader.ReadHalfSingle(),
dataReader.ReadHalfSingle(),
dataReader.ReadHalfSingle());
}
else if (att.DataType == 0x000D || att.DataType == 0x0D00)
{
vertex.col = new Vector4(
dataReader.ReadByte() / 255f,
dataReader.ReadByte() / 255f,
dataReader.ReadByte() / 255f,
dataReader.ReadByte() / 255f);
}
}
else //Cloth layer
{
}
break;
case VertexAttriubte.Weights:
if (att.DataType == 0x0000)
{
vertex.boneWeights.Add(dataReader.ReadSingle());
float value2 = 1.0f - vertex.boneWeights[0];
vertex.boneWeights.Add(value2);
}
else if (att.DataType == 0x0001 || att.DataType == 0x0100)
{
vertex.boneWeights.Add(dataReader.ReadSingle());
vertex.boneWeights.Add(dataReader.ReadSingle());
float z = 1.0f - vertex.boneWeights[0] - vertex.boneWeights[1];
vertex.boneWeights.Add(z);
}
else if (att.DataType == 0x0002 || att.DataType == 0x0200)
{
for (int j = 0; j < 3; j++)
vertex.boneWeights.Add(dataReader.ReadSingle());
var value4 = 1 - vertex.boneWeights[0] - vertex.boneWeights[1] - vertex.boneWeights[2];
vertex.boneWeights.Add(value4);
}
else if (att.DataType == 0x0003 || att.DataType == 0x0300)
{
for (int j = 0; j < 4; j++)
vertex.boneWeights.Add(dataReader.ReadSingle());
}
else if (att.DataType == 0x000A || att.DataType == 0x0A00)
{
vertex.boneWeights.Add(dataReader.ReadHalfSingle());
vertex.boneWeights.Add(dataReader.ReadHalfSingle());
float z = 1.0f - vertex.boneWeights[0] - vertex.boneWeights[1];
vertex.boneWeights.Add(z);
}
else if (att.DataType == 0x000B || att.DataType == 0x0B00)
{
for (int j = 0; j < 4; j++)
vertex.boneWeights.Add(dataReader.ReadHalfSingle());
}
else if (att.DataType == 0x000D || att.DataType == 0x0D00)
{
for (int j = 0; j < 4; j++)
vertex.boneWeights.Add(dataReader.ReadByte() / 255f);
}
break;
case VertexAttriubte.BoneIndices:
if (att.DataType == 0x0005 || att.DataType == 0x0500)
{
for (int j = 0; j < 4; j++)
vertex.boneIds.Add(dataReader.ReadByte());
}
else if (att.DataType == 0x0007 || att.DataType == 0x0700)
{
for (int j = 0; j < 4; j++)
vertex.boneIds.Add(dataReader.ReadUInt16());
}
else if (att.DataType == 0x000D || att.DataType == 0x0D00)
{
for (int j = 0; j < 4; j++)
vertex.boneIds.Add(dataReader.ReadByte());
}
break;
}
}
if (vertex.boneWeights.All(x => x == 0))
{
vertex.boneIds.Clear();
vertex.boneWeights.Clear();
vertex.boneIds.Add((int)skinningList.JointIndices[0]);
vertex.boneWeights.Add(1);
}
else if (vertex.boneWeights.Count > 0)
{
for (int j = 0; j < vertex.boneIds.Count; j++)
{
int id = vertex.boneIds[j] / 3;
if (skinningList.JointIndices.Length > id)
id = (int)skinningList.JointIndices[id];
vertex.boneIds[j] = id;
}
}
}
}
return vertices;
}
}
public struct BoundingBox
{
public Vector3 Min { get; set; }
public Vector3 Max { get; set; }
}
public class Material : STGenericMaterial, IChunk
{
public uint Unknown1;
public uint Unknown2;
public uint Unknown3;
public List<ushort[]> TextureIndices;
public G1MTextureMap Diffuse;
public void Read(FileReader reader) {
Unknown1 = reader.ReadUInt32(); //0
uint numTextures = reader.ReadUInt32();
Unknown2 = reader.ReadUInt32(); //0, 1, -1
Unknown3 = reader.ReadUInt32(); //0, 1, -1
TextureIndices = new List<ushort[]>();
for (int i = 0; i < numTextures; i++)
TextureIndices.Add(reader.ReadUInt16s(6));
Diffuse = new G1MTextureMap();
Diffuse.Type = STGenericMatTexture.TextureType.Diffuse;
TextureMaps.Add(Diffuse);
}
public void Write(FileWriter writer) {
writer.Write(Unknown1);
writer.Write(TextureIndices.Count);
writer.Write(Unknown2);
writer.Write(Unknown3);
foreach (var indices in TextureIndices)
writer.Write(indices);
}
}
public class G1MTextureMap : STGenericMatTexture
{
public int TextureIndex { get; set; } = -1;
}
public class ShaderData : IChunk
{
public void Read(FileReader reader)
{
}
public void Write(FileWriter writer)
{
}
}
public class VertexBuffer : IChunk
{
public uint Unknown1 { get; set; }
public uint Stride { get; set; }
public uint ElementCount { get; set; }
public uint Unknown2 { get; set; }
public byte[] BufferData { get; set; }
public void Read(FileReader reader) {
Unknown1 = reader.ReadUInt32();
Stride = reader.ReadUInt32();
ElementCount = reader.ReadUInt32();
Unknown2 = reader.ReadUInt32();
BufferData = reader.ReadBytes((int)(ElementCount * Stride));
}
public void Write(FileWriter writer) {
writer.Write(Unknown1);
writer.Write(Stride);
writer.Write(ElementCount);
writer.Write(Unknown2);
writer.Write(BufferData);
}
}
public class VertexAttributeList : IChunk
{
public List<VertexAttribute> Attributes = new List<VertexAttribute>();
public void Read(FileReader reader)
{
uint numBuffers = reader.ReadUInt32();
int[] bufferIndices = reader.ReadInt32s((int)numBuffers);
uint numAttributes = reader.ReadUInt32();
for (int i = 0; i < numAttributes; i++)
{
var buffer = new VertexAttribute();
buffer.BufferIndex = bufferIndices[(int)reader.ReadUInt16()];
buffer.Offset = reader.ReadUInt16();
byte flag1 = reader.ReadByte();
byte flag2 = reader.ReadByte();
buffer.DataType = (ushort)((flag1 << 8) | flag2);
buffer.AttributeType = (VertexAttriubte)reader.ReadByte();
buffer.Layer = reader.ReadByte();
Attributes.Add(buffer);
}
}
public void Write(FileWriter writer)
{
writer.Write(Attributes.Count);
}
}
public class VertexAttribute
{
public int BufferIndex { get; set; }
public ushort Offset { get; set; }
public ushort DataType { get; set; }
public VertexAttriubte AttributeType { get; set; }
public byte Layer { get; set; }
}
public class JointMapInfo : IChunk
{
public uint[] UnkIndices { get; set; }
public uint[] JointIndices { get; set; }
public uint[] ClothIndices { get; set; }
public void Read(FileReader reader)
{
uint numJoints = reader.ReadUInt32();
UnkIndices = new uint[(int)numJoints];
JointIndices = new uint[(int)numJoints];
ClothIndices = new uint[(int)numJoints];
for (int i = 0; i < numJoints; i++) {
UnkIndices[i] = reader.ReadUInt32();
ClothIndices[i] = reader.ReadUInt32() & 0xFFFF;
JointIndices[i] = reader.ReadUInt32() & 0xFFFF;
}
}
public void Write(FileWriter writer)
{
writer.Write(JointIndices.Length);
for (int i = 0; i < JointIndices.Length; i++) {
writer.Write(UnkIndices[i]);
writer.Write(ClothIndices[i]);
writer.Write(JointIndices[i]);
} }
} }
} }
public class IndexBuffer : IChunk
{
public uint ElementCount { get; set; }
public FaceType DataType { get; set; }
public uint Unknown1 { get; set; }
public uint Stride
{
get
{
if (DataType == FaceType.Byte) return 1;
else if (DataType == FaceType.UInt16) return 2;
else if (DataType == FaceType.UInt32) return 4;
else
throw new Exception("Unknown index stride! " + DataType);
}
}
public byte[] BufferData { get; set; }
public IEnumerable<uint> GetIndices(bool isBigEndian, uint offset, uint elementCount)
{
using (var reader = new FileReader(BufferData))
{
reader.SetByteOrder(isBigEndian);
reader.SeekBegin(offset * Stride);
switch (DataType)
{
case FaceType.Byte:
for (; elementCount > 0; elementCount--)
{
yield return reader.ReadByte();
}
break;
case FaceType.UInt16:
for (; elementCount > 0; elementCount--)
{
yield return reader.ReadUInt16();
}
break;
case FaceType.UInt32:
for (; elementCount > 0; elementCount--)
{
yield return reader.ReadUInt32();
}
break;
default:
throw new Exception("Unknown type! " + DataType);
}
}
}
public void Read(FileReader reader)
{
ElementCount = reader.ReadUInt32();
DataType = reader.ReadEnum<FaceType>(true);
Unknown1 = reader.ReadUInt32();
BufferData = reader.ReadBytes((int)(ElementCount * Stride));
reader.Align(4);
}
public void Write(FileWriter writer)
{
writer.Write(ElementCount);
writer.Write(DataType, true);
writer.Write(Stride);
writer.Write(Unknown1);
writer.Write(BufferData);
writer.Align(4);
}
}
public class SubMeshInfo : IChunk
{
public uint UnknownIndex;
public uint VertexBufferID;
public uint IndexIntoJointMap;
public uint Unknown2;
public uint TextureCount;
public uint MaterialID;
public uint TextureID;
public uint IndexBufferID;
public uint Unknown;
public uint IndexBufferFormat;
public uint VertexBufferOffset;
public uint VertexBufferCount;
public uint IndexBufferOffset;
public uint IndexBufferCount;
public void Read(FileReader reader)
{
UnknownIndex = reader.ReadUInt32();
VertexBufferID = reader.ReadUInt32();
IndexIntoJointMap = reader.ReadUInt32();
Unknown2 = reader.ReadUInt32();
TextureCount = reader.ReadUInt32();
MaterialID = reader.ReadUInt32();
TextureID = reader.ReadUInt32();
IndexBufferID = reader.ReadUInt32();
Unknown = reader.ReadUInt32();
IndexBufferFormat = reader.ReadUInt32();
VertexBufferOffset = reader.ReadUInt32();
VertexBufferCount = reader.ReadUInt32();
IndexBufferOffset = reader.ReadUInt32();
IndexBufferCount = reader.ReadUInt32();
}
public void Write(FileWriter writer)
{
writer.Write(UnknownIndex);
writer.Write(VertexBufferID);
writer.Write(IndexIntoJointMap);
writer.Write(Unknown2);
writer.Write(TextureCount);
writer.Write(MaterialID);
writer.Write(TextureID);
writer.Write(IndexBufferID);
writer.Write(Unknown);
writer.Write(IndexBufferFormat);
writer.Write(VertexBufferOffset);
writer.Write(VertexBufferCount);
writer.Write(IndexBufferOffset);
writer.Write(IndexBufferCount);
}
}
public class LodGroup : IChunk
{
public List<LodMesh> Meshes = new List<LodMesh>();
public void Read(FileReader reader)
{
reader.ReadUInt32();
reader.ReadUInt32();
reader.ReadUInt32();
uint numMeshes1 = reader.ReadUInt32();
uint numMeshes2 = reader.ReadUInt32();
reader.ReadUInt32();
reader.ReadUInt32();
reader.ReadUInt32();
reader.ReadUInt32();
for (int i = 0; i < numMeshes1 + numMeshes2; i++) {
LodMesh msh = new LodMesh();
Meshes.Add(msh);
msh.Name = reader.ReadString(16, true);
msh.ID = reader.ReadUInt32();
msh.ID2 = reader.ReadUInt32();
uint numIndces = reader.ReadUInt32();
msh.Indices = reader.ReadUInt32s((int)numIndces);
if (numIndces == 0)
reader.ReadUInt32();
}
}
public void Write(FileWriter writer)
{
}
}
public class LodMesh
{
public string Name { get; set; }
public uint ID { get; set; }
public uint ID2 { get; set; }
public uint[] Indices { get; set; }
}
} }

View File

@ -4,14 +4,63 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Toolbox.Library.IO; using Toolbox.Library.IO;
using Toolbox.Library;
namespace HyruleWarriors.G1M namespace HyruleWarriors.G1M
{ {
public class G1MS : G1MChunkCommon public class G1MS : G1MChunkCommon
{ {
public G1MS(FileReader reader) public STSkeleton GenericSkeleton = new STSkeleton();
{
public short[] BoneIndices { get; set; }
public G1MS ChildSkeleton { get; set; }
public ushort[] BoneIndexList { get; set; }
public G1MS(FileReader reader, bool isParent = true)
{
uint pos = (uint)reader.Position - 12;
uint boneOffset = reader.ReadUInt32() + pos;
ushort conditionNumber = reader.ReadUInt16();
if (isParent && conditionNumber == 0)
{
}
ushort unknown = reader.ReadUInt16();
ushort numBones = reader.ReadUInt16();
ushort numBoneIndices = reader.ReadUInt16();
BoneIndices = reader.ReadInt16s((int)numBoneIndices);
BoneIndexList = new ushort[numBones];
for (ushort i = 0; i < BoneIndices?.Length; i++)
if (BoneIndices[i] != -1)
BoneIndexList[BoneIndices[i]] = i;
reader.SeekBegin(boneOffset);
for (int i = 0; i < numBones; i++) {
var scale = reader.ReadVec3();
int parentIndex = reader.ReadInt32();
var quat = reader.ReadQuaternion(true);
var position = reader.ReadVec3();
reader.ReadSingle();
// if ((parentIndex & 0x80000000) > 0 && parentIndex != -1)
// parentIndex = parentIndex & 0x7FFFFFFF;
STBone genericBone = new STBone(GenericSkeleton);
genericBone.Text = $"Bone {BoneIndexList[i]}";
genericBone.Rotation = quat;
genericBone.Scale = scale;
genericBone.Position = position;
genericBone.parentIndex = parentIndex;
GenericSkeleton.bones.Add(genericBone);
}
GenericSkeleton.reset();
GenericSkeleton.update();
} }
} }
} }

View File

@ -0,0 +1,160 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Toolbox.Library.IO;
using OpenTK;
namespace HyruleWarriors.G1M
{
public class NUNO
{
public List<NUNOType0303Struct> NUNO0303StructList = new List<NUNOType0303Struct>();
public class NUNOType0303Struct
{
public int Unknown { get; set; }
public int BoneParentID { get; set; }
public Vector4[] Points { get; set; }
public NUNOInfluence[] Influences { get; set; }
public int Unknown2 { get; set; }
public int Unknown3 { get; set; }
public int Unknown4 { get; set; }
}
public struct NUNOInfluence
{
public int P1 { get; set; }
public int P2 { get; set; }
public int P3 { get; set; }
public int P4 { get; set; }
public float P5 { get; set; }
public float P6 { get; set; }
}
public NUNO(FileReader reader, uint version)
{
uint numChunks = reader.ReadUInt32();
for (int i = 0; i < numChunks; i++)
{
long pos = reader.Position;
uint subchunkMagic = reader.ReadUInt32();
uint subchunkSize = reader.ReadUInt32();
uint subChunkCount = reader.ReadUInt32();
for (int j = 0; j < subChunkCount; j++)
{
switch(subchunkMagic)
{
case 0x00030001:
NUNO0303StructList.Add(ParseNUNOSection0301(reader, version));
break;
case 0x00030002:
ParseNUNOSection0302(reader, version);
break;
case 0x00030003:
NUNO0303StructList.Add(ParseNUNOSection0303(reader, version));
break;
case 0x00030004:
ParseNUNOSection0304(reader, version);
break;
default:
Console.WriteLine("Unknown chunk! " + subchunkMagic.ToString());
break;
}
}
reader.SeekBegin(pos + subchunkSize);
}
}
public NUNOType0303Struct ParseNUNOSection0301(FileReader reader, uint version)
{
var nuno301 = new NUNOType0303Struct();
nuno301.Unknown = reader.ReadInt32();
uint numControlPoints = reader.ReadUInt32();
uint unkCount = reader.ReadUInt32();
nuno301.Unknown2 = reader.ReadInt32();
nuno301.Unknown3 = reader.ReadInt32();
nuno301.Unknown4 = reader.ReadInt32();
reader.ReadInt32();
reader.ReadInt32();
nuno301.BoneParentID = reader.ReadInt32();
reader.ReadBytes(0x40);
if (version >= 0x30303235)
reader.ReadBytes(0x10);
nuno301.Influences = new NUNOInfluence[(int)numControlPoints];
nuno301.Points = new Vector4[(int)numControlPoints];
for (int i = 0; i < numControlPoints; i++)
nuno301.Points[i] = reader.ReadVec4();
for (int i = 0; i < numControlPoints; i++) {
var influence = new NUNOInfluence();
influence.P1 = reader.ReadInt32();
influence.P2 = reader.ReadInt32();
influence.P3 = reader.ReadInt32();
influence.P4 = reader.ReadInt32();
influence.P5 = reader.ReadSingle();
influence.P6 = reader.ReadSingle();
nuno301.Influences[i] = influence;
}
reader.Seek(48 * unkCount);
reader.Seek(4 * nuno301.Unknown2);
reader.Seek(4 * nuno301.Unknown3);
reader.Seek(4 * nuno301.Unknown4);
return nuno301;
}
public void ParseNUNOSection0302(FileReader reader, uint version)
{
}
public NUNOType0303Struct ParseNUNOSection0303(FileReader reader, uint version)
{
var nuno301 = new NUNOType0303Struct();
nuno301.Unknown = reader.ReadInt32();
uint numControlPoints = reader.ReadUInt32();
uint unkCount = reader.ReadUInt32();
nuno301.Unknown2 = reader.ReadInt32();
nuno301.BoneParentID = reader.ReadInt32();
nuno301.Unknown3 = reader.ReadInt32();
reader.ReadBytes(0xB0);
if (version >= 0x30303235)
reader.ReadBytes(0x10);
nuno301.Influences = new NUNOInfluence[(int)numControlPoints];
nuno301.Points = new Vector4[(int)numControlPoints];
for (int i = 0; i < numControlPoints; i++)
nuno301.Points[i] = reader.ReadVec4();
for (int i = 0; i < numControlPoints; i++)
{
var influence = new NUNOInfluence();
influence.P1 = reader.ReadInt32();
influence.P2 = reader.ReadInt32();
influence.P3 = reader.ReadInt32();
influence.P4 = reader.ReadInt32();
influence.P5 = reader.ReadSingle();
influence.P6 = reader.ReadSingle();
nuno301.Influences[i] = influence;
}
reader.Seek(48 * unkCount);
reader.Seek(4 * nuno301.Unknown2);
reader.Seek(8 * nuno301.Unknown3);
return nuno301;
}
public void ParseNUNOSection0304(FileReader reader, uint version)
{
}
}
}

View File

@ -0,0 +1,76 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Toolbox.Library.IO;
using OpenTK;
namespace HyruleWarriors.G1M
{
public class NUNV
{
public List<NUNO.NUNOType0303Struct> NUNV0303StructList = new List<NUNO.NUNOType0303Struct>();
public NUNV(FileReader reader, uint version)
{
uint numChunks = reader.ReadUInt32();
for (int i = 0; i < numChunks; i++)
{
long pos = reader.Position;
uint subchunkMagic = reader.ReadUInt32();
uint subchunkSize = reader.ReadUInt32();
uint subChunkCount = reader.ReadUInt32();
for (int j = 0; j < subChunkCount; j++)
{
switch (subchunkMagic)
{
case 0x00050001:
NUNV0303StructList.Add(ParseNUVOSection0501(reader, version));
break;
default:
Console.WriteLine("Unknown chunk! " + subchunkMagic.ToString());
break;
}
}
reader.SeekBegin(pos + subchunkSize);
}
}
public NUNO.NUNOType0303Struct ParseNUVOSection0501(FileReader reader, uint version)
{
var nuno501 = new NUNO.NUNOType0303Struct();
nuno501.Unknown = reader.ReadInt32();
uint numControlPoints = reader.ReadUInt32();
uint unkCount = reader.ReadUInt32();
nuno501.Unknown2 = reader.ReadInt32();
nuno501.BoneParentID = reader.ReadInt32();
reader.ReadBytes(0x50);
if (version >= 0x30303131)
reader.ReadBytes(0x10);
nuno501.Influences = new NUNO.NUNOInfluence[(int)numControlPoints];
nuno501.Points = new Vector4[(int)numControlPoints];
for (int i = 0; i < numControlPoints; i++)
nuno501.Points[i] = reader.ReadVec4();
for (int i = 0; i < numControlPoints; i++)
{
var influence = new NUNO.NUNOInfluence();
influence.P1 = reader.ReadInt32();
influence.P2 = reader.ReadInt32();
influence.P3 = reader.ReadInt32();
influence.P4 = reader.ReadInt32();
influence.P5 = reader.ReadSingle();
influence.P6 = reader.ReadSingle();
nuno501.Influences[i] = influence;
}
reader.Seek(48 * unkCount);
reader.Seek(4 * nuno501.Unknown2);
return nuno501;
}
}
}

View File

@ -63,6 +63,8 @@ namespace FirstPlugin
G1TFile.Read(new FileReader(stream)); G1TFile.Read(new FileReader(stream));
for (int i = 0; i < G1TFile.Textures.Count; i++) for (int i = 0; i < G1TFile.Textures.Count; i++)
Nodes.Add(G1TFile.Textures[i]); Nodes.Add(G1TFile.Textures[i]);
PluginRuntime.G1TextureContainers.Add(this);
} }
public void Save(System.IO.Stream stream) public void Save(System.IO.Stream stream)
@ -73,7 +75,7 @@ namespace FirstPlugin
public void Unload() public void Unload()
{ {
PluginRuntime.G1TextureContainers.Remove(this);
} }
public virtual ToolStripItem[] GetContextMenuItems() public virtual ToolStripItem[] GetContextMenuItems()

View File

@ -7,6 +7,7 @@ using Toolbox;
using System.Windows.Forms; using System.Windows.Forms;
using Toolbox.Library; using Toolbox.Library;
using Toolbox.Library.IO; using Toolbox.Library.IO;
using HyruleWarriors.G1M;
namespace FirstPlugin namespace FirstPlugin
{ {
@ -28,7 +29,13 @@ namespace FirstPlugin
public bool Identify(System.IO.Stream stream) public bool Identify(System.IO.Stream stream)
{ {
return (FileName.Contains(".bin.gz")); using (var reader = new FileReader(stream, true))
{
bool isTexture = reader.CheckSignature(4, "G1TG") || reader.CheckSignature(4, "GT1G");
bool isModel = reader.CheckSignature(4, "_M1G") || reader.CheckSignature(4, "G1M_");
return (FileName.Contains(".bin.gz")) && !isTexture && !isModel;
}
} }
public Type[] Types public Type[] Types
@ -63,6 +70,20 @@ namespace FirstPlugin
public bool isBigEndian = true; public bool isBigEndian = true;
public override void OnAfterAdded()
{
var editor = LibraryGUI.GetObjectEditor();
foreach (var file in files)
{
if (file.FileFormat == null)
continue;
if (file.FileFormat is G1M)
editor.SelectNode((G1M)file.FileFormat);
}
}
public void Load(Stream stream) public void Load(Stream stream)
{ {
CanSave = true; CanSave = true;
@ -94,16 +115,21 @@ namespace FirstPlugin
reader.SeekBegin(Offsets[i]); reader.SeekBegin(Offsets[i]);
fileEntry.FileData = reader.ReadBytes((int)Sizes[i]); fileEntry.FileData = reader.ReadBytes((int)Sizes[i]);
fileEntry.FileName = $"File {i}"; fileEntry.FileName = $"File {i}";
fileEntry.OpenFileFormatOnLoad = true;
switch (Magic) switch (Magic)
{ {
case "GT1G": //Textures case "GT1G": //Textures
case "G1TG": //Textures case "G1TG": //Textures
G1T GITextureU = new G1T(); fileEntry.FileName = $"TextureContainer_{i}.gt1";
GITextureU.FileName = $"TextureContainer{i}.gt1"; break;
GITextureU.Load(new MemoryStream(fileEntry.FileData)); case "_M1G":
Nodes.Add(GITextureU); case "G1M_":
fileEntry.FileFormat = GITextureU; fileEntry.FileName = $"Model_{i}.g1m";
break;
case "_A1G":
case "G1A_":
fileEntry.FileName = $"Animation_{i}.g1a";
break; break;
default: default:
break; break;

View File

@ -477,18 +477,9 @@ namespace FirstPlugin
boneNode.RotationType = STBone.BoneRotationType.Euler; boneNode.RotationType = STBone.BoneRotationType.Euler;
boneNode.Checked = true; boneNode.Checked = true;
boneNode.Text = Node.Name; boneNode.Text = Node.Name;
boneNode.position = new float[3]; boneNode.Position = Node.Translation;
boneNode.scale = new float[3]; boneNode.EulerRotation = Node.Rotation;
boneNode.rotation = new float[4]; boneNode.Scale = Node.Scale;
boneNode.position[0] = Node.Translation.X;
boneNode.position[1] = Node.Translation.Y;
boneNode.position[2] = Node.Translation.Z;
boneNode.rotation[0] = Node.Rotation.X;
boneNode.rotation[1] = Node.Rotation.Y;
boneNode.rotation[2] = Node.Rotation.Z;
boneNode.scale[0] = Node.Scale.X;
boneNode.scale[1] = Node.Scale.Y;
boneNode.scale[2] = Node.Scale.Z;
if (Node.IsBone) if (Node.IsBone)
Skeleton.bones.Add(boneNode); Skeleton.bones.Add(boneNode);

View File

@ -479,18 +479,9 @@ namespace FirstPlugin
boneNode.RotationType = STBone.BoneRotationType.Euler; boneNode.RotationType = STBone.BoneRotationType.Euler;
boneNode.Checked = true; boneNode.Checked = true;
boneNode.Text = Node.Name; boneNode.Text = Node.Name;
boneNode.position = new float[3]; boneNode.Position = Node.Translation;
boneNode.scale = new float[3]; boneNode.EulerRotation = Node.Rotation;
boneNode.rotation = new float[4]; boneNode.Scale = Node.Scale;
boneNode.position[0] = Node.Translation.X;
boneNode.position[1] = Node.Translation.Y;
boneNode.position[2] = Node.Translation.Z;
boneNode.rotation[0] = Node.Rotation.X;
boneNode.rotation[1] = Node.Rotation.Y;
boneNode.rotation[2] = Node.Rotation.Z;
boneNode.scale[0] = Node.Scale.X;
boneNode.scale[1] = Node.Scale.Y;
boneNode.scale[2] = Node.Scale.Z;
if (Node.IsBone) if (Node.IsBone)
Skeleton.bones.Add(boneNode); Skeleton.bones.Add(boneNode);

View File

@ -0,0 +1,56 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SharpYaml.Serialization;
namespace FirstPlugin
{
public class MSYT
{
public static string ToYaml(MSBT msbt)
{
var header = MessageHeader.FromMSBT(msbt);
var serializer = new Serializer();
return serializer.Serialize(header);
}
public class MessageHeader
{
public List<MessageEntry> entries = new List<MessageEntry>();
public static MessageHeader FromMSBT(MSBT msbt)
{
MessageHeader header = new MessageHeader();
for (int i = 0; i < msbt.header.Label1.Labels.Count; i++) {
var entry = msbt.header.Label1.Labels[i];
var msgEntry = new MessageEntry();
msgEntry.Name = entry.Name;
msgEntry.contents.text.Add(entry.String.GetText(msbt.header.StringEncoding));
header.entries.Add(msgEntry);
}
return header;
}
}
public class MessageEntry
{
public Content contents = new Content();
[YamlIgnore]
public string Name { get; set; }
public override string ToString()
{
return Name;
}
}
public class Content
{
public List<string> text = new List<string>();
}
}
}

View File

@ -296,11 +296,12 @@ namespace FirstPlugin.LuigisMansion.DarkMoon
if (NLG_Common.HashNames.ContainsKey(HashID)) if (NLG_Common.HashNames.ContainsKey(HashID))
bone.Text = NLG_Common.HashNames[HashID]; bone.Text = NLG_Common.HashNames[HashID];
bone.position = new float[3] { Position.X, Position.Z, -Position.Y };
bone.rotation = new float[4] { Rotate.X, Rotate.Z, -Rotate.Y, 1 };
bone.scale = new float[3] { 0.2f, 0.2f, 0.2f };
bone.Position = Position;
bone.EulerRotation = Rotate;
bone.Scale = new OpenTK.Vector3(0.2f, 0.2f, 0.2f);
bone.RotationType = STBone.BoneRotationType.Euler; bone.RotationType = STBone.BoneRotationType.Euler;
currentModel.Skeleton.bones.Add(bone); currentModel.Skeleton.bones.Add(bone);
} }

View File

@ -611,11 +611,9 @@ namespace FirstPlugin.NLG
if (HashList.ContainsKey(bone.HashID)) if (HashList.ContainsKey(bone.HashID))
stBone.Text = HashList[bone.HashID]; stBone.Text = HashList[bone.HashID];
stBone.position = new float[3] { bone.Translate.X, bone.Translate.Z, -bone.Translate.Y }; stBone.Position = bone.Translate;
stBone.rotation = new float[4] { bone.Rotate.X, bone.Rotate.Z, -bone.Rotate.Y, 1 }; stBone.EulerRotation = bone.Rotate;
stBone.Scale = new Vector3(0.2f, 0.2f, 0.2f);
// stBone.scale = new float[3] { bone.Scale.X, bone.Scale.Y, bone.Scale.Z };
stBone.scale = new float[3] { 0.2f, 0.2f, 0.2f };
stBone.RotationType = STBone.BoneRotationType.Euler; stBone.RotationType = STBone.BoneRotationType.Euler;
} }

View File

@ -214,32 +214,31 @@ namespace FirstPlugin.PunchOutWii
reader.ReadUInt32(); //unk reader.ReadUInt32(); //unk
reader.ReadUInt32(); //unk reader.ReadUInt32(); //unk
reader.ReadSingle(); //0 reader.ReadSingle(); //0
STBone bone = new STBone(Skeleton);
var Scale = new OpenTK.Vector3( var Scale = new OpenTK.Vector3(
reader.ReadSingle(), reader.ReadSingle(),
reader.ReadSingle(), reader.ReadSingle(),
reader.ReadSingle()); reader.ReadSingle());
reader.ReadSingle(); //0 reader.ReadSingle(); //0
var Rotate = new OpenTK.Vector3( bone.EulerRotation = new OpenTK.Vector3(
reader.ReadSingle(), reader.ReadSingle(),
reader.ReadSingle(), reader.ReadSingle(),
reader.ReadSingle()); reader.ReadSingle());
reader.ReadSingle(); //0 reader.ReadSingle(); //0
var Position = new OpenTK.Vector3( bone.Position = new OpenTK.Vector3(
reader.ReadSingle(), reader.ReadSingle(),
reader.ReadSingle(), reader.ReadSingle(),
reader.ReadSingle()); reader.ReadSingle());
reader.ReadSingle(); //1 reader.ReadSingle(); //1
STBone bone = new STBone(Skeleton);
bone.Text = HashID.ToString("X"); bone.Text = HashID.ToString("X");
if (NLG_Common.HashNames.ContainsKey(HashID)) if (NLG_Common.HashNames.ContainsKey(HashID))
bone.Text = NLG_Common.HashNames[HashID]; bone.Text = NLG_Common.HashNames[HashID];
else else
Console.WriteLine($"bone hash {HashID}"); Console.WriteLine($"bone hash {HashID}");
bone.position = new float[3] { Position.X, Position.Z, -Position.Y }; bone.Scale = new Vector3(0.2f, 0.2f, 0.2f);
bone.rotation = new float[4] { Rotate.X, Rotate.Z, -Rotate.Y, 1 };
bone.scale = new float[3] { 0.2f, 0.2f, 0.2f };
bone.RotationType = STBone.BoneRotationType.Euler; bone.RotationType = STBone.BoneRotationType.Euler;
Skeleton.bones.Add(bone); Skeleton.bones.Add(bone);

View File

@ -199,24 +199,9 @@ namespace FirstPlugin
{ {
STBone bone = new STBone(Skeleton); STBone bone = new STBone(Skeleton);
bone.parentIndex = Joints[i].ParentIndex; bone.parentIndex = Joints[i].ParentIndex;
bone.position = new float[] bone.Position = Joints[i].Position;
{ bone.EulerRotation = Joints[i].Rotation;
Joints[i].Position.X, bone.Scale = Joints[i].Scale;
Joints[i].Position.Y,
Joints[i].Position.Z,
};
bone.scale = new float[]
{
Joints[i].Scale.X,
Joints[i].Scale.Y,
Joints[i].Scale.Z,
};
bone.rotation = new float[]
{
Joints[i].Rotation.X,
Joints[i].Rotation.Y,
Joints[i].Rotation.Z,
};
Skeleton.bones.Add(bone); Skeleton.bones.Add(bone);
} }
Skeleton.reset(); Skeleton.reset();

View File

@ -225,7 +225,7 @@ namespace FirstPlugin
} }
else else
{ {
b.rot = EulerToQuat(b.rotation[2], b.rotation[1], b.rotation[0]); b.rot = EulerToQuat(b.EulerRotation.Z, b.EulerRotation.Y, b.EulerRotation.X);
} }
} }
} }

View File

@ -370,9 +370,9 @@ namespace FirstPlugin
List<int> SkinningIndices = new List<int>(); List<int> SkinningIndices = new List<int>();
foreach (var genericBone in skeleton.bones) foreach (var genericBone in skeleton.bones)
{ {
var scale = genericBone.scale; var scale = genericBone.Scale;
var trans = genericBone.position; var trans = genericBone.Position;
var rot = genericBone.rotation; var rot = genericBone.EulerRotation;
Bone bone = new Bone(); Bone bone = new Bone();
bone.Name = genericBone.Text; bone.Name = genericBone.Text;
@ -380,9 +380,9 @@ namespace FirstPlugin
bone.Parent = genericBone.parentIndex; bone.Parent = genericBone.parentIndex;
bone.Zero = 0; bone.Zero = 0;
bone.Visible = false; bone.Visible = false;
bone.Scale = new GFMDLStructs.Vector3(scale[0], scale[1], scale[2]); bone.Scale = new GFMDLStructs.Vector3(scale.X, scale.Y, scale.Z);
bone.Rotation = new GFMDLStructs.Vector3(rot[0], rot[1], rot[2]); bone.Rotation = new GFMDLStructs.Vector3(rot.X, rot.Y, rot.Z);
bone.Translation = new GFMDLStructs.Vector3(trans[0], trans[1], trans[2]); bone.Translation = new GFMDLStructs.Vector3(trans.X, trans.Y, trans.Z);
bone.RadiusStart = new GFMDLStructs.Vector3(0, 0, 0); bone.RadiusStart = new GFMDLStructs.Vector3(0, 0, 0);
bone.RadiusEnd = new GFMDLStructs.Vector3(0, 0, 0); bone.RadiusEnd = new GFMDLStructs.Vector3(0, 0, 0);
@ -524,7 +524,7 @@ namespace FirstPlugin
for (int j = 0; j < mesh.vertices[i].boneNames?.Count; j++) for (int j = 0; j < mesh.vertices[i].boneNames?.Count; j++)
{ {
string boneName = mesh.vertices[i].boneNames[j]; string boneName = mesh.vertices[i].boneNames[j] ;
int boneIndex = Model.Model.Bones.IndexOf(Model.Model.Bones.Where(p => p.Name == boneName).FirstOrDefault()); int boneIndex = Model.Model.Bones.IndexOf(Model.Model.Bones.Where(p => p.Name == boneName).FirstOrDefault());
if (boneIndex != -1 && skinningIndices.IndexOf(boneIndex) != -1) if (boneIndex != -1 && skinningIndices.IndexOf(boneIndex) != -1)

View File

@ -356,7 +356,10 @@ namespace FirstPlugin
matTexture.Type = STGenericMatTexture.TextureType.Normal; matTexture.Type = STGenericMatTexture.TextureType.Normal;
break; break;
case "AmbientTex": case "AmbientTex":
matTexture.Type = STGenericMatTexture.TextureType.AO; if (SwitchParams.ContainsKey("AmbientMapEnable")) {
if (SwitchParams["AmbientMapEnable"].Value)
matTexture.Type = STGenericMatTexture.TextureType.AO;
}
break; break;
case "LightTblTex": case "LightTblTex":
break; break;
@ -441,30 +444,29 @@ namespace FirstPlugin
if (bone.Translation != null) if (bone.Translation != null)
{ {
position = new float[3] Position = new OpenTK.Vector3(
{ bone.Translation.X, bone.Translation.X,
bone.Translation.Y, bone.Translation.Y,
bone.Translation.Z bone.Translation.Z
}; );
} }
if (bone.Rotation != null) if (bone.Rotation != null)
{ {
rotation = new float[4] EulerRotation = new OpenTK.Vector3(
{ bone.Rotation.X, bone.Rotation.X,
bone.Rotation.Y, bone.Rotation.Y,
bone.Rotation.Z, bone.Rotation.Z
1.0f, );
};
} }
if (bone.Scale != null) if (bone.Scale != null)
{ {
scale = new float[3] Scale = new OpenTK.Vector3(
{ bone.Scale.X, bone.Scale.X,
bone.Scale.Y, bone.Scale.Y,
bone.Scale.Z bone.Scale.Z
}; );
} }
} }
} }

View File

@ -229,8 +229,12 @@
<Compile Include="FileFormats\BCH\Wrappers\SkeletalAnimation\H3DSkeletalAnimWrapper.cs" /> <Compile Include="FileFormats\BCH\Wrappers\SkeletalAnimation\H3DSkeletalAnimWrapper.cs" />
<Compile Include="FileFormats\Byaml\XmlByamlConverter.cs" /> <Compile Include="FileFormats\Byaml\XmlByamlConverter.cs" />
<Compile Include="FileFormats\Byaml\YamlByamlConverter.cs" /> <Compile Include="FileFormats\Byaml\YamlByamlConverter.cs" />
<Compile Include="FileFormats\HyruleWarriors\G1M\G1MCommon.cs" />
<Compile Include="FileFormats\HyruleWarriors\G1M\NUNO.cs" />
<Compile Include="FileFormats\HyruleWarriors\G1M\NUNV.cs" />
<Compile Include="FileFormats\LM1\LM1_MDL.cs" /> <Compile Include="FileFormats\LM1\LM1_MDL.cs" />
<Compile Include="FileFormats\MarioParty\HSF.cs" /> <Compile Include="FileFormats\MarioParty\HSF.cs" />
<Compile Include="FileFormats\Message\MSYT.cs" />
<Compile Include="FileFormats\MKAGPDX\LM2_ARCADE_Model.cs" /> <Compile Include="FileFormats\MKAGPDX\LM2_ARCADE_Model.cs" />
<Compile Include="FileFormats\NLG\LM2\LM2_Material.cs" /> <Compile Include="FileFormats\NLG\LM2\LM2_Material.cs" />
<Compile Include="FileFormats\NLG\LM3\LM3_ChunkTable.cs" /> <Compile Include="FileFormats\NLG\LM3\LM3_ChunkTable.cs" />
@ -318,7 +322,6 @@
<Compile Include="FileFormats\Effects\PTCL_3DS.cs" /> <Compile Include="FileFormats\Effects\PTCL_3DS.cs" />
<Compile Include="FileFormats\Effects\PTCL_WiiU.cs" /> <Compile Include="FileFormats\Effects\PTCL_WiiU.cs" />
<Compile Include="FileFormats\Font\BFFNT.cs" /> <Compile Include="FileFormats\Font\BFFNT.cs" />
<Compile Include="FileFormats\Font\BFOTF.cs" />
<Compile Include="FileFormats\Audio\Archives\BFGRP.cs" /> <Compile Include="FileFormats\Audio\Archives\BFGRP.cs" />
<Compile Include="FileFormats\Font\BffntCharSet2Xlor.cs" /> <Compile Include="FileFormats\Font\BffntCharSet2Xlor.cs" />
<Compile Include="FileFormats\Font\BFTTF.cs" /> <Compile Include="FileFormats\Font\BFTTF.cs" />
@ -397,6 +400,7 @@
<Compile Include="GL\BFRES\BFRESRenderBase.cs" /> <Compile Include="GL\BFRES\BFRESRenderBase.cs" />
<Compile Include="GL\BMD_Renderer.cs" /> <Compile Include="GL\BMD_Renderer.cs" />
<Compile Include="GL\CMB_Renderer.cs" /> <Compile Include="GL\CMB_Renderer.cs" />
<Compile Include="GL\G1M_Renderer.cs" />
<Compile Include="GL\GXToOpenGL.cs" /> <Compile Include="GL\GXToOpenGL.cs" />
<Compile Include="GL\KCL_Render.cs" /> <Compile Include="GL\KCL_Render.cs" />
<Compile Include="GL\LM2_Render.cs" /> <Compile Include="GL\LM2_Render.cs" />

View File

@ -0,0 +1,67 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Toolbox.Library.Rendering;
using GL_EditorFramework.GL_Core;
using GL_EditorFramework.Interfaces;
using OpenTK;
using OpenTK.Graphics.OpenGL;
using Toolbox.Library;
using FirstPlugin;
namespace HyruleWarriors.G1M
{
public class G1M_Renderer : GenericModelRenderer
{
public G1M G1MFile { get; set; }
public List<ushort> SkinningIndices { get; set; }
public override void OnRender(GLControl control)
{
}
public override void SetRenderData(STGenericMaterial mat, ShaderProgram shader, STGenericObject m)
{
shader.SetBoolToInt("NoSkinning", Skeleton.bones.Count == 0);
if (mat.Text == "driver_cloth")
{
GL.Disable(EnableCap.CullFace);
}
else
{
GL.Enable(EnableCap.CullFace);
}
}
public override int BindTexture(STGenericMatTexture tex, ShaderProgram shader)
{
GL.ActiveTexture(TextureUnit.Texture0 + tex.textureUnit + 1);
GL.BindTexture(TextureTarget.Texture2D, RenderTools.defaultTex.RenderableTex.TexID);
string activeTex = tex.Name;
foreach (var texContainer in PluginRuntime.G1TextureContainers)
{
if (G1MFile.IFileInfo.ArchiveParent != texContainer.IFileInfo.ArchiveParent)
continue;
var textureList = texContainer.TextureList;
foreach (var texture in texContainer.TextureList)
{
if (textureList.IndexOf(texture) == ((G1MTextureMap)tex).TextureIndex)
{
BindGLTexture(tex, shader, textureList[((G1MTextureMap)tex).TextureIndex]);
return tex.textureUnit + 1;
}
}
}
return tex.textureUnit + 1;
}
}
}

View File

@ -131,45 +131,61 @@ namespace FirstPlugin
private void SetBoneTransform(BfresBone bn) private void SetBoneTransform(BfresBone bn)
{ {
bn.position[0] = (float)posXUD.Value; bn.Position = new OpenTK.Vector3(
bn.position[1] = (float)posYUD.Value; (float)posXUD.Value,
bn.position[2] = (float)posZUD.Value; (float)posYUD.Value,
(float)posZUD.Value
);
bn.rotation[0] = (float)RotXUD.Value; if ((BoneFlagsRotation)rotModeCB.SelectedItem == BoneFlagsRotation.Quaternion)
bn.rotation[1] = (float)RotYUD.Value;
bn.rotation[2] = (float)RotZUD.Value;
bn.rotation[3] = (float)RotWUD.Value;
bn.scale[0] = (float)ScaXUD.Value;
bn.scale[1] = (float)ScaYUD.Value;
bn.scale[2] = (float)ScaZUD.Value;
if (bn.BoneU != null)
{ {
bn.BoneU.Position = new Syroot.Maths.Vector3F(bn.position[0], bn.position[1], bn.position[2]); bn.Rotation = new OpenTK.Quaternion(
bn.BoneU.Rotation = new Syroot.Maths.Vector4F(bn.rotation[0], bn.rotation[1], bn.rotation[2], bn.rotation[3]); (float)RotXUD.Value,
bn.BoneU.Scale = new Syroot.Maths.Vector3F(bn.scale[0], bn.scale[1], bn.scale[2]); (float)RotYUD.Value,
(float)RotZUD.Value,
(float)RotWUD.Value
);
} }
else else
{ {
bn.Bone.Position = new Syroot.Maths.Vector3F(bn.position[0], bn.position[1], bn.position[2]); bn.EulerRotation = new OpenTK.Vector3(
bn.Bone.Rotation = new Syroot.Maths.Vector4F(bn.rotation[0], bn.rotation[1], bn.rotation[2], bn.rotation[3]); (float)RotXUD.Value,
bn.Bone.Scale = new Syroot.Maths.Vector3F(bn.scale[0], bn.scale[1], bn.scale[2]); (float)RotYUD.Value,
(float)RotZUD.Value
);
} }
bn.Scale = new OpenTK.Vector3(
(float)ScaXUD.Value,
(float)ScaYUD.Value,
(float)ScaZUD.Value
);
bn.GenericToBfresBone();
} }
private void GetBoneTransform(STBone bn) private void GetBoneTransform(STBone bn)
{ {
posXUD.Value = (decimal)bn.position[0]; posXUD.Value = (decimal)bn.Position.X;
posYUD.Value = (decimal)bn.position[1]; posYUD.Value = (decimal)bn.Position.Y;
posZUD.Value = (decimal)bn.position[2]; posZUD.Value = (decimal)bn.Position.Z;
RotXUD.Value = (decimal)bn.rotation[0]; if (bn.RotationType == STBone.BoneRotationType.Quaternion) {
RotYUD.Value = (decimal)bn.rotation[1]; RotXUD.Value = (decimal)bn.Rotation.X;
RotZUD.Value = (decimal)bn.rotation[2]; RotYUD.Value = (decimal)bn.Rotation.Y;
RotWUD.Value = (decimal)bn.rotation[3]; RotZUD.Value = (decimal)bn.Rotation.Z;
ScaXUD.Value = (decimal)bn.scale[0]; RotWUD.Value = (decimal)bn.Rotation.W;
ScaYUD.Value = (decimal)bn.scale[1]; }
ScaZUD.Value = (decimal)bn.scale[2]; else
{
RotXUD.Value = (decimal)bn.EulerRotation.X;
RotYUD.Value = (decimal)bn.EulerRotation.Y;
RotZUD.Value = (decimal)bn.EulerRotation.Z;
RotWUD.Value = (decimal)1.0f;
}
ScaXUD.Value = (decimal)bn.Scale.X;
ScaYUD.Value = (decimal)bn.Scale.Y;
ScaZUD.Value = (decimal)bn.Scale.Z;
} }
private void rotMeasureCB_SelectedIndexChanged(object sender, EventArgs e) private void rotMeasureCB_SelectedIndexChanged(object sender, EventArgs e)
@ -206,17 +222,7 @@ namespace FirstPlugin
if (activeBone == null || !IsLoaded) if (activeBone == null || !IsLoaded)
return; return;
if ((BoneFlagsRotation)rotModeCB.SelectedItem == BoneFlagsRotation.Quaternion) SetBoneTransform(activeBone);
{
activeBone.ConvertToQuaternion();
SetBoneTransform(activeBone);
}
else
{
activeBone.ConvertToEular();
SetBoneTransform(activeBone);
}
LibraryGUI.UpdateViewport(); LibraryGUI.UpdateViewport();
} }

View File

@ -406,14 +406,13 @@ namespace FirstPlugin
Formats.Add(typeof(GCDisk)); Formats.Add(typeof(GCDisk));
Formats.Add(typeof(TPL)); Formats.Add(typeof(TPL));
Formats.Add(typeof(BFTTF)); Formats.Add(typeof(BFTTF));
Formats.Add(typeof(BFOTF));
Formats.Add(typeof(HedgehogLibrary.PACx)); Formats.Add(typeof(HedgehogLibrary.PACx));
Formats.Add(typeof(BinGzArchive));
Formats.Add(typeof(GAR)); Formats.Add(typeof(GAR));
Formats.Add(typeof(CTXB)); Formats.Add(typeof(CTXB));
Formats.Add(typeof(CSAB)); Formats.Add(typeof(CSAB));
Formats.Add(typeof(CMB)); Formats.Add(typeof(CMB));
Formats.Add(typeof(G1T)); Formats.Add(typeof(G1T));
Formats.Add(typeof(HyruleWarriors.G1M.G1M));
Formats.Add(typeof(LayoutBXLYT.Cafe.BFLYT)); Formats.Add(typeof(LayoutBXLYT.Cafe.BFLYT));
Formats.Add(typeof(LayoutBXLYT.BCLYT)); Formats.Add(typeof(LayoutBXLYT.BCLYT));
Formats.Add(typeof(LayoutBXLYT.BRLYT)); Formats.Add(typeof(LayoutBXLYT.BRLYT));
@ -449,6 +448,7 @@ namespace FirstPlugin
Formats.Add(typeof(CtrLibrary.BCH)); Formats.Add(typeof(CtrLibrary.BCH));
Formats.Add(typeof(LZS)); Formats.Add(typeof(LZS));
Formats.Add(typeof(WTA)); Formats.Add(typeof(WTA));
Formats.Add(typeof(BinGzArchive));
@ -458,10 +458,8 @@ namespace FirstPlugin
//Unfinished wip formats not ready for use //Unfinished wip formats not ready for use
if (Runtime.DEVELOPER_DEBUG_MODE) if (Runtime.DEVELOPER_DEBUG_MODE)
{ {
Formats.Add(typeof(XLINK));
Formats.Add(typeof(BFSAR)); Formats.Add(typeof(BFSAR));
Formats.Add(typeof(GFA)); Formats.Add(typeof(GFA));
Formats.Add(typeof(HyruleWarriors.G1M.G1M));
} }

View File

@ -30,6 +30,8 @@ namespace FirstPlugin
public static List<CtrLibrary.BCHGroupNode> bchTexContainers = new List<CtrLibrary.BCHGroupNode>(); public static List<CtrLibrary.BCHGroupNode> bchTexContainers = new List<CtrLibrary.BCHGroupNode>();
public static List<NLG.StrikersRLT.TextureEntry> stikersTextures = new List<NLG.StrikersRLT.TextureEntry>(); public static List<NLG.StrikersRLT.TextureEntry> stikersTextures = new List<NLG.StrikersRLT.TextureEntry>();
public static List<G1T> G1TextureContainers = new List<G1T>();
public static string ExternalFMATPath = ""; public static string ExternalFMATPath = "";
public static string OdysseyGamePath = ""; public static string OdysseyGamePath = "";
public static string Mk8GamePath = ""; public static string Mk8GamePath = "";

View File

@ -1,314 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Aampv1 = AampV1Library;
using Aampv2 = AampV2Library;
using System.IO;
using Syroot.Maths;
using SharpYaml;
using SharpYaml.Events;
using SharpYaml.Serialization;
using SharpYaml.Serialization.Serializers;
namespace FirstPlugin
{
public static class StringExtensions
{
public static string Indent(this string value, int size)
{
var strArray = value.Split('\n');
var sb = new StringBuilder();
foreach (var s in strArray)
sb.Append(new string(' ', size)).Append(s);
return sb.ToString();
}
}
public class AampYamlConverter
{
public class YamlAamp
{
public const string Identifier = "!aamp";
public string version { get; set; }
}
#region V1 AAMP
public static string ToYaml(Aampv1.AampFile aampFile)
{
StringBuilder sb = new StringBuilder();
using (TextWriter writer = new StringWriter(sb))
{
writer.WriteLine("!aamp");
writer.WriteLine($"version: {aampFile.Version}");
writer.WriteLine("!io");
writer.WriteLine($"version: 0");
writer.WriteLine($"type: {aampFile.EffectType}");
WriteParamList(writer, aampFile.RootNode, 0);
}
return sb.ToString();
}
private static void WriteParamList(TextWriter writer, Aampv1.ParamList paramList, int IndentAmount)
{
writer.WriteLine($"{paramList.HashString}: !list".Indent(IndentAmount));
if (paramList.paramObjects.Length <= 0)
writer.WriteLine("objects: {}".Indent(IndentAmount + 2));
else
writer.WriteLine("objects: ".Indent(IndentAmount + 2));
foreach (var paramObj in paramList.paramObjects)
{
WriteParamObject(writer, paramObj, IndentAmount + 4);
}
if (paramList.childParams.Length <= 0)
writer.WriteLine("lists: {}".Indent(IndentAmount + 2));
else
writer.WriteLine("lists: ".Indent(IndentAmount + 2));
foreach (var child in paramList.childParams)
{
WriteParamList(writer, child, IndentAmount + 4);
}
}
private static void WriteParamObject(TextWriter writer, Aampv1.ParamObject paramObj, int IndentAmount)
{
writer.WriteLine($"{paramObj.HashString} : !obj".Indent(IndentAmount));
foreach (var entry in paramObj.paramEntries)
{
writer.WriteLine($"{entry.HashString}: {WriteParamData(entry)}".Indent(IndentAmount + 2));
}
}
private static string WriteParamData(Aampv1.ParamEntry entry)
{
switch (entry.ParamType)
{
case Aampv1.ParamType.Boolean: return $"{(bool)entry.Value}";
case Aampv1.ParamType.BufferBinary: return $"!BufferBinary [ {WriteBytes((byte[])entry.Value)} ]";
case Aampv1.ParamType.BufferFloat: return $"!BufferFloat [ {WriteFloats((float[])entry.Value)} ]";
case Aampv1.ParamType.BufferInt: return $"BufferInt [ {WriteInts((int[])entry.Value)} ]";
case Aampv1.ParamType.BufferUint: return $"!BufferUint [ {WriteUints((uint[])entry.Value)} ]";
case Aampv1.ParamType.Color4F: return $"{WriteColor4F((Vector4F)entry.Value)}";
case Aampv1.ParamType.Vector2F: return $"{WriteVec2F((Vector2F)entry.Value)}";
case Aampv1.ParamType.Vector3F: return $"{WriteVec3F((Vector3F)entry.Value)}";
case Aampv1.ParamType.Vector4F: return $"{WriteVec4F((Vector4F)entry.Value)}";
case Aampv1.ParamType.Uint: return $"{(uint)entry.Value}";
case Aampv1.ParamType.Int: return $"{(int)entry.Value}";
case Aampv1.ParamType.Float: return $"{(float)entry.Value}";
case Aampv1.ParamType.String256: return $"!str256 {WriteStringEntry((AampCommon.StringEntry)entry.Value)}";
case Aampv1.ParamType.String32: return $"!str32 {WriteStringEntry((AampCommon.StringEntry)entry.Value)}";
case Aampv1.ParamType.String64: return $"!str64 {WriteStringEntry((AampCommon.StringEntry)entry.Value)}";
case Aampv1.ParamType.StringRef: return $"!strRef {WriteStringEntry((AampCommon.StringEntry)entry.Value)}";
case Aampv1.ParamType.Curve1: return $"{WriteCurve((Aampv1.Curve[])entry.Value, 1)}";
case Aampv1.ParamType.Curve2: return $"{WriteCurve((Aampv1.Curve[])entry.Value, 2)}";
case Aampv1.ParamType.Curve3: return $"{WriteCurve((Aampv1.Curve[])entry.Value, 3)}";
case Aampv1.ParamType.Curve4: return $"{WriteCurve((Aampv1.Curve[])entry.Value, 4)}";
default:
throw new Exception("Unsupported type! " + entry.ParamType);
}
}
private static string WriteStringEntry(AampCommon.StringEntry value)
{
return BytesToStringConverted(value.Data).Replace(" ", string.Empty);
// return Encoding.Default.GetString(value.Data).Replace(" ", string.Empty);
}
static string BytesToStringConverted(byte[] bytes)
{
using (var stream = new MemoryStream(bytes))
{
using (var reader = new Toolbox.Library.IO.FileReader(stream))
{
return reader.ReadZeroTerminatedString();
}
}
}
private static string WriteCurve(Aampv1.Curve[] curves, int Num)
{
string curveStr = "";
foreach (var curve in curves)
curveStr += $"!curve{Num}[{WriteUints(curve.valueUints)}] [{WriteFloats(curve.valueFloats)}] \n";
return curveStr;
}
//I could've used a yaml parser, but incase i need to change it up to look nicer and support leo's aamp layout, do it manually
public static void ToAamp(Aampv1.AampFile aampFile, string text)
{
byte[] TextData = Encoding.Unicode.GetBytes(text);
StreamReader t = new StreamReader(new MemoryStream(TextData), Encoding.GetEncoding(932));
var yaml = new YamlStream();
yaml.Load(new StringReader(text));
/* var mapping = (YamlMappingNode)yaml.Documents[0].RootNode;
foreach (var item in mapping.AllNodes)
{
Console.WriteLine("n " + item);
}*/
/* byte[] TextData = Encoding.Unicode.GetBytes(text);
StreamReader t = new StreamReader(new MemoryStream(TextData), Encoding.GetEncoding(932));
using (var reader = new StringReader(t.ReadToEnd()))
{
string AampCheck = reader.ReadLine();
if (AampCheck != "!aamp")
throw new Exception($"Expected !aamp got {AampCheck} at line 0");
string VersionCheck = reader.ReadLine();
string num = GetProperty(VersionCheck);
if (num == "1")
{
}
}*/
}
public static void ParseList(StringReader reader)
{
}
public static string GetProperty(string line)
{
if (line.Contains(":"))
return line.Split(':')[1].Replace(string.Empty, "");
return line;
}
#endregion
#region V2 AAMP
public static string ToYaml(Aampv2.AampFile aampFile)
{
StringBuilder sb = new StringBuilder();
using (TextWriter writer = new StringWriter(sb))
{
writer.WriteLine("!aamp");
writer.WriteLine($"version: {aampFile.Version}");
writer.WriteLine("!io");
writer.WriteLine($"version: {aampFile.ParameterIOVersion}");
writer.WriteLine($"type: {aampFile.ParameterIOType}");
WriteParamList(writer, aampFile.RootNode, 0);
}
return sb.ToString();
}
private static void WriteParamList(TextWriter writer, Aampv2.ParamList paramList, int IndentAmount)
{
writer.WriteLine($"{paramList.HashString}: !list".Indent(IndentAmount));
if (paramList.paramObjects.Length <= 0)
writer.WriteLine("objects: {}".Indent(IndentAmount + 2));
else
writer.WriteLine("objects: ".Indent(IndentAmount + 2));
foreach (var paramObj in paramList.paramObjects)
{
WriteParamObject(writer, paramObj, IndentAmount + 4);
}
if (paramList.childParams.Length <= 0)
writer.WriteLine("lists: {}".Indent(IndentAmount + 2));
else
writer.WriteLine("lists: ".Indent(IndentAmount + 2));
foreach (var child in paramList.childParams)
{
WriteParamList(writer, child, IndentAmount + 4);
}
}
private static void WriteParamObject(TextWriter writer, Aampv2.ParamObject paramObj, int IndentAmount)
{
writer.WriteLine($"{paramObj.HashString} : !obj".Indent(IndentAmount));
foreach (var entry in paramObj.paramEntries)
{
writer.WriteLine($"{WriteParamData(entry)}".Indent(IndentAmount + 2));
}
}
private static string WriteParamData(Aampv2.ParamEntry entry)
{
switch (entry.ParamType)
{
case Aampv2.ParamType.Boolean: return $"{entry.HashString}: {(bool)entry.Value}";
case Aampv2.ParamType.BufferBinary: return $"{entry.HashString}: !BufferBinary [ {WriteBytes((byte[])entry.Value)} ]";
case Aampv2.ParamType.BufferFloat: return $"{entry.HashString}: !BufferFloat [ {WriteFloats((float[])entry.Value)} ]";
case Aampv2.ParamType.BufferInt: return $"{entry.HashString}: !BufferInt [ {WriteInts((int[])entry.Value)} ]";
case Aampv2.ParamType.BufferUint: return $"{entry.HashString}: !BufferUint [ {WriteUints((uint[])entry.Value)} ]";
case Aampv2.ParamType.Quat: return $"{entry.HashString}: !BufferUint [ {WriteFloats((float[])entry.Value)} ]";
case Aampv2.ParamType.Color4F: return $"{entry.HashString}: {WriteColor4F((Vector4F)entry.Value)}";
case Aampv2.ParamType.Vector2F: return $"{entry.HashString}: {WriteVec2F((Vector2F)entry.Value)}";
case Aampv2.ParamType.Vector3F: return $"{entry.HashString}: {WriteVec3F((Vector3F)entry.Value)}";
case Aampv2.ParamType.Vector4F: return $"{entry.HashString}: {WriteVec4F((Vector4F)entry.Value)}";
case Aampv2.ParamType.Uint: return $"{entry.HashString}: {(uint)entry.Value}";
case Aampv2.ParamType.Int: return $"{entry.HashString}: {(int)entry.Value}";
case Aampv2.ParamType.Float: return $"{entry.HashString}: {(float)entry.Value}";
case Aampv2.ParamType.String256: return $"{entry.HashString}: !str256 {((AampCommon.StringEntry)entry.Value).ToString()}";
case Aampv2.ParamType.String32: return $"{entry.HashString}: !str32 {((AampCommon.StringEntry)entry.Value).ToString()}";
case Aampv2.ParamType.String64: return $"{entry.HashString}: !str64 {((AampCommon.StringEntry)entry.Value).ToString()}";
case Aampv2.ParamType.StringRef: return $"{entry.HashString}: !strRef {((AampCommon.StringEntry)entry.Value).ToString()}";
case Aampv2.ParamType.Curve1: return $"{entry.HashString}: {WriteCurve((Aampv2.Curve[])entry.Value, 1)}";
case Aampv2.ParamType.Curve2: return $"{entry.HashString}: {WriteCurve((Aampv2.Curve[])entry.Value, 2)}";
case Aampv2.ParamType.Curve3: return $"{entry.HashString}: {WriteCurve((Aampv2.Curve[])entry.Value, 3)}";
case Aampv2.ParamType.Curve4: return $"{entry.HashString}: {WriteCurve((Aampv2.Curve[])entry.Value, 4)}";
default:
throw new Exception("Unsupported type! " + entry.ParamType);
}
}
private static string WriteCurve(Aampv2.Curve[] curves, int Num)
{
string curveStr = "";
foreach (var curve in curves)
curveStr += $"!curve{Num}[{WriteUints(curve.valueUints)}] [{WriteFloats(curve.valueFloats)}] \n";
return curveStr;
}
public static Aampv2.AampFile ToAamp(string FileName)
{
var aampFile = new Aampv2.AampFile();
return aampFile;
}
#endregion
private static string WriteUints(uint[] arr) {
return String.Join(",", arr.Select(p => p.ToString()).ToArray());
}
private static string WriteFloats(float[] arr) {
return String.Join(",", arr.Select(p => p.ToString()).ToArray());
}
private static string WriteInts(int[] arr) {
return String.Join(",", arr.Select(p => p.ToString()).ToArray());
}
private static string WriteBytes(byte[] arr) {
return String.Join(",", arr.Select(p => p.ToString()).ToArray());
}
private static string WriteVec2F(Vector2F vec2) { return $"!vec2[{vec2.X}, {vec2.Y}]"; }
private static string WriteVec3F(Vector3F vec3) { return $"!vec3[{vec3.X}, {vec3.Y}, {vec3.Z}]"; }
private static string WriteVec4F(Vector4F vec4) { return $"!vec4[{vec4.X}, {vec4.Y}, {vec4.Z}, {vec4.W}]"; }
private static string WriteColor4F(Vector4F vec4) { return $"!color[{vec4.X}, {vec4.Y}, {vec4.Z}, {vec4.W}]"; }
}
}

View File

@ -202,30 +202,6 @@ namespace Toolbox.Library.Animations
return sca; return sca;
} }
public void SetKeyFromBone(float frame, STBone bone)
{
Vector3 rot = ANIM.quattoeul(bone.rot);
if (rot.X != bone.rotation[0] || rot.Y != bone.rotation[1] || rot.Z != bone.rotation[2])
{
XROT.GetKeyFrame(frame).Value = bone.rot.X;
YROT.GetKeyFrame(frame).Value = bone.rot.Y;
ZROT.GetKeyFrame(frame).Value = bone.rot.Z;
WROT.GetKeyFrame(frame).Value = bone.rot.W;
}
if (bone.pos.X != bone.position[0] || bone.pos.Y != bone.position[1] || bone.pos.Z != bone.position[2])
{
XPOS.GetKeyFrame(frame).Value = bone.pos.X;
YPOS.GetKeyFrame(frame).Value = bone.pos.Y;
ZPOS.GetKeyFrame(frame).Value = bone.pos.Z;
}
if (bone.sca.X != bone.scale[0] || bone.sca.Y != bone.scale[1] || bone.sca.Z != bone.scale[2])
{
XSCA.GetKeyFrame(frame).Value = bone.sca.X;
YSCA.GetKeyFrame(frame).Value = bone.sca.Y;
ZSCA.GetKeyFrame(frame).Value = bone.sca.Z;
}
}
} }
public void ReplaceMe(Animation a) public void ReplaceMe(Animation a)
@ -291,29 +267,22 @@ namespace Toolbox.Library.Animations
public KeyFrame GetKeyFrame(float frame, bool InsertNewKey = true) public KeyFrame GetKeyFrame(float frame, bool InsertNewKey = true)
{ {
KeyFrame key = null; if (Keys.Count == 0) return null;
int i; KeyFrame k1 = (KeyFrame)Keys[0], k2 = (KeyFrame)Keys[0];
for (i = 0; i < Keys.Count; i++) foreach (KeyFrame k in Keys)
{ {
if (Keys[i].Frame == frame) if (k.Frame < frame)
{ {
key = Keys[i]; k1 = k;
break;
} }
if (Keys[i].Frame > frame) else
{ {
k2 = k;
break; break;
} }
} }
if (key == null && InsertNewKey) return k1;
{
key = new KeyFrame();
key.Frame = frame;
Keys.Insert(i, key);
}
return key;
} }
public bool SetValue(float Value, int frame) public bool SetValue(float Value, int frame)
@ -330,36 +299,6 @@ namespace Toolbox.Library.Animations
return false; return false;
} }
public KeyFrame GetLeft(int frame)
{
KeyFrame prev = Keys[0];
for (int i = 0; i < Keys.Count - 1; i++)
{
KeyFrame key = Keys[i];
if (key.Frame > frame && prev.Frame <= frame)
break;
prev = key;
}
return prev;
}
public KeyFrame GetRight(int frame)
{
KeyFrame cur = Keys[0];
KeyFrame prev = Keys[0];
for (int i = 1; i < Keys.Count; i++)
{
KeyFrame key = Keys[i];
cur = key;
if (key.Frame > frame && prev.Frame <= frame)
break;
prev = key;
}
return cur;
}
int LastFound = 0; int LastFound = 0;
float LastFrame; float LastFrame;
@ -368,71 +307,52 @@ namespace Toolbox.Library.Animations
if (Keys.Count == 0) if (Keys.Count == 0)
return 0; return 0;
KeyFrame k1 = (KeyFrame)Keys[0], k2 = (KeyFrame)Keys[0]; float startFrame = Keys.First().Frame;
int i = 0;
if (frame < LastFrame) KeyFrame LK = Keys.First();
LastFound = 0; KeyFrame RK = Keys.Last();
for (i = LastFound; i < Keys.Count; i++)
foreach (KeyFrame keyFrame in Keys)
{ {
LastFound = i % (Keys.Count); if (keyFrame.Frame <= frame) LK = keyFrame;
KeyFrame k = Keys[LastFound]; if (keyFrame.Frame >= frame && keyFrame.Frame < RK.Frame) RK = keyFrame;
if (k.Frame < frame) }
if (LK.Frame != RK.Frame)
{
// float FrameDiff = frame - LK.Frame;
// float Weight = 1.0f / (RK.Frame - LK.Frame);
// float Weight = FrameDiff / (RK.Frame - LK.Frame);
float FrameDiff = frame - LK.Frame;
float Weight = FrameDiff / (RK.Frame - LK.Frame);
Console.WriteLine($"frame diff {FrameDiff} frame {frame} LK {LK.Frame} RK {RK} ratio {Weight}");
switch (InterpolationType)
{ {
k1 = k; case InterpolationType.CONSTANT: return LK.Value;
} case InterpolationType.STEP: return LK.Value;
else case InterpolationType.LINEAR: return InterpolationHelper.Lerp(LK.Value, RK.Value, Weight);
{ case InterpolationType.HERMITE:
k2 = k; // return InterpolationHelper.GetCubicValue(Weight, LK.Value, LK.Slope1, LK.Slope2, LK.Delta);
break; // return CubicEval(LK.Value, LK.Slope1, LK.Slope2, LK.Delta, ratio);
float length = RK.Frame - LK.Frame;
float val = InterpolationHelper.HermiteInterpolate(frame,
LK.Frame,
RK.Frame,
RK.Slope1,
LK.Slope2,
LK.Value,
RK.Value);
return val;
} }
} }
LastFound -= 1; return LK.Value;
if (LastFound < 0)
LastFound = 0;
if (LastFound >= Keys.Count - 2)
LastFound = 0;
LastFrame = frame;
if (k1.InterType == InterpolationType.CONSTANT)
return k1.Value;
if (k1.InterType == InterpolationType.STEP)
return k1.Value;
if (k1.InterType == InterpolationType.LINEAR)
{
return Lerp(k1.Value, k2.Value, k1.Frame, k2.Frame, frame);
}
if (k1.InterType == InterpolationType.HERMITE)
{
float val = Hermite(frame, k1.Frame, k2.Frame, k1.In, k1.Out != -1 ? k1.Out : k2.In, k1.Value, k2.Value) * (k1.Degrees ? (float)Math.PI / 180 : 1);
if (float.IsNaN(val)) val = k1._value;
if (frame == k1.Frame) return k1.Value;
if (frame == k2.Frame) return k2.Value;
float distance = frame - k1.Frame;
float invDuration = 1f / (k2.Frame - k1.Frame);
float t = distance * invDuration;
float p0 = k1.Value;
float p1 = k2.Value;
float s0 = k1.Out * distance;
float s1 = k2.In * distance;
float cf0 = (p0 * 2) + (p1 * -2) + (s0 * 1) + (s1 * 1);
float cf1 = (p0 * -3) + (p1 * 3) + (s0 * -2) + (s1 * -1);
float cf2 = (p0 * 0) + (p1 * 0) + (s0 * 1) + (s1 * 0);
float cf3 = (p0 * 1) + (p1 * 0) + (s0 * 0) + (s1 * 0);
return val;//k1.Out != -1 ? k1.Out :
return CubicEval(cf0, cf1, cf2, cf3, t);
}
return k1.Value;
} }
public KeyFrame[] GetFrame(float frame) public KeyFrame[] GetFrame(float frame)
{ {
if (Keys.Count == 0) return null; if (Keys.Count == 0) return null;
@ -596,9 +516,9 @@ namespace Toolbox.Library.Animations
else else
if (node.RotType == RotationType.EULER) if (node.RotType == RotationType.EULER)
{ {
float x = node.XROT.HasAnimation() ? node.XROT.GetValue(Frame) : b.rotation[0]; float x = node.XROT.HasAnimation() ? node.XROT.GetValue(Frame) : b.EulerRotation.X;
float y = node.YROT.HasAnimation() ? node.YROT.GetValue(Frame) : b.rotation[1]; float y = node.YROT.HasAnimation() ? node.YROT.GetValue(Frame) : b.EulerRotation.Y;
float z = node.ZROT.HasAnimation() ? node.ZROT.GetValue(Frame) : b.rotation[2]; float z = node.ZROT.HasAnimation() ? node.ZROT.GetValue(Frame) : b.EulerRotation.Z;
b.rot = EulerToQuat(z, y, x); b.rot = EulerToQuat(z, y, x);
} }
} }
@ -644,32 +564,13 @@ namespace Toolbox.Library.Animations
public static float CubicEval(float cf0, float cf1, float cf2, float cf3, float t) public static float CubicEval(float cf0, float cf1, float cf2, float cf3, float t)
{ {
return (((cf0 * t + cf1) * t + cf2) * t + cf3); return ((cf3 * t + cf2) * t) * t + (cf1 * t + cf0);
// return (((cf0 * t + cf1) * t + cf2) * t + cf3);
} }
public static float Hermite(float frame, float frame1, float frame2, float outslope, float inslope, float val1, float val2) public static float Hermite(float frame, float frame1, float frame2, float outSlope, float inSlope, float val1, float val2)
{ {
/*float offset = frame - frame1;
float span = frame2 - frame1;
if (offset == 0) return val1;
if (offset == span) return val2;
float diff = val2 - val1;
float time = offset / span;
//bool prevDouble = prevframe1 >= 0 && prevframe1 == frame1 - 1;
//bool nextDouble = next._next._index >= 0 && next._next._index == next._index + 1;
bool oneApart = frame2 == frame1 + 1;
float tan = outslope, nextTan = inslope;
if (oneApart)
tan = (val2 - val1) / (frame2 - frame1);
//if (oneApart)
nextTan = (val2 - val1) / (frame2 - frame1);
float inv = time - 1.0f; //-1 to 0
return val1
+ (offset * inv * ((inv * tan) + (time * nextTan)))
+ ((time * time) * (3.0f - 2.0f * time) * diff);*/
if (frame == frame1) return val1; if (frame == frame1) return val1;
if (frame == frame2) return val2; if (frame == frame2) return val2;
@ -677,7 +578,7 @@ namespace Toolbox.Library.Animations
float invDuration = 1f / (frame2 - frame1); float invDuration = 1f / (frame2 - frame1);
float t = distance * invDuration; float t = distance * invDuration;
float t1 = t - 1f; float t1 = t - 1f;
return (val1 + ((((val1 - val2) * ((2f * t) - 3f)) * t) * t)) + ((distance * t1) * ((t1 * outslope) + (t * inslope))); return (val1 + ((((val1 - val2) * ((2f * t) - 3f)) * t) * t)) + ((distance * t1) * ((t1 * outSlope) + (t * inSlope)));
} }
public static float Lerp(float av, float bv, float v0, float v1, float t) public static float Lerp(float av, float bv, float v0, float v1, float t)

View File

@ -36,17 +36,17 @@ namespace Toolbox.Library.Animations
if (seanim.AnimType == AnimationType.Relative) if (seanim.AnimType == AnimationType.Relative)
{ {
PositionX = genericBone.position[0]; PositionX = genericBone.Position.X;
PositionY = genericBone.position[1]; PositionY = genericBone.Position.Y;
PositionZ = genericBone.position[2]; PositionZ = genericBone.Position.Z;
RotationX = genericBone.rotation[0]; RotationX = genericBone.EulerRotation.X;
RotationY = genericBone.rotation[1]; RotationY = genericBone.EulerRotation.Y;
RotationZ = genericBone.rotation[2]; RotationZ = genericBone.EulerRotation.Z;
ScaleX = genericBone.scale[0]; ScaleX = genericBone.Scale.X;
ScaleY = genericBone.scale[1]; ScaleY = genericBone.Scale.Y;
ScaleZ = genericBone.scale[2]; ScaleZ = genericBone.Scale.Z;
} }
System.Console.WriteLine(bone); System.Console.WriteLine(bone);

View File

@ -68,18 +68,15 @@ namespace Toolbox.Library.Animations
if (time == 0) if (time == 0)
{ {
STBone b = BoneList[int.Parse(args[0])]; STBone b = BoneList[int.Parse(args[0])];
b.position = new float[3]; b.Position = new Vector3(
b.rotation = new float[3]; float.Parse(args[1]),
b.scale = new float[3]; float.Parse(args[2]),
b.position[0] = float.Parse(args[1]); float.Parse(args[3]));
b.position[1] = float.Parse(args[2]); b.EulerRotation = new Vector3(
b.position[2] = float.Parse(args[3]); float.Parse(args[4]),
b.rotation[0] = float.Parse(args[4]); float.Parse(args[5]),
b.rotation[1] = float.Parse(args[5]); float.Parse(args[6]));
b.rotation[2] = float.Parse(args[6]); b.Scale = Vector3.One;
b.scale[0] = 1f;
b.scale[1] = 1f;
b.scale[2] = 1f;
b.pos = new Vector3(float.Parse(args[1]), float.Parse(args[2]), float.Parse(args[3])); b.pos = new Vector3(float.Parse(args[1]), float.Parse(args[2]), float.Parse(args[3]));
b.rot = STSkeleton.FromEulerAngles(float.Parse(args[6]), float.Parse(args[5]), float.Parse(args[4])); b.rot = STSkeleton.FromEulerAngles(float.Parse(args[6]), float.Parse(args[5]), float.Parse(args[4]));
@ -113,7 +110,13 @@ namespace Toolbox.Library.Animations
for (int i = 0; i < Bones.bones.Count; i++) for (int i = 0; i < Bones.bones.Count; i++)
{ {
STBone b = Bones.bones[i]; STBone b = Bones.bones[i];
o.AppendFormat("{0} {1} {2} {3} {4} {5} {6}\n", i, b.position[0], b.position[1], b.position[2], b.rotation[0], b.rotation[1], b.rotation[2]); o.AppendFormat("{0} {1} {2} {3} {4} {5} {6}\n", i,
b.Position.X,
b.Position.Y,
b.Position.Z,
b.EulerRotation.X,
b.EulerRotation.Y,
b.EulerRotation.Z);
} }
o.AppendLine("end"); o.AppendLine("end");
} }
@ -182,18 +185,15 @@ namespace Toolbox.Library.Animations
if (readBones && frame == 0) if (readBones && frame == 0)
{ {
STBone b = vbn.bones[int.Parse(args[0])]; STBone b = vbn.bones[int.Parse(args[0])];
b.position = new float[3]; b.Position = new Vector3(
b.rotation = new float[3]; float.Parse(args[1]),
b.scale = new float[3]; float.Parse(args[2]),
b.position[0] = float.Parse(args[1]); float.Parse(args[3]));
b.position[1] = float.Parse(args[2]); b.EulerRotation = new Vector3(
b.position[2] = float.Parse(args[3]); float.Parse(args[4]),
b.rotation[0] = float.Parse(args[4]); float.Parse(args[5]),
b.rotation[1] = float.Parse(args[5]); float.Parse(args[6]));
b.rotation[2] = float.Parse(args[6]); b.Scale = Vector3.One;
b.scale[0] = 1f;
b.scale[1] = 1f;
b.scale[2] = 1f;
b.pos = new Vector3(float.Parse(args[1]), float.Parse(args[2]), float.Parse(args[3])); b.pos = new Vector3(float.Parse(args[1]), float.Parse(args[2]), float.Parse(args[3]));
b.rot = STSkeleton.FromEulerAngles(float.Parse(args[6]), float.Parse(args[5]), float.Parse(args[4])); b.rot = STSkeleton.FromEulerAngles(float.Parse(args[6]), float.Parse(args[5]), float.Parse(args[4]));

View File

@ -73,7 +73,6 @@ namespace Toolbox.Library
scene = Importer.ImportFile(FileName, settings.GetFlags()); scene = Importer.ImportFile(FileName, settings.GetFlags());
if (Utils.GetExtension(FileName) == ".dae") if (Utils.GetExtension(FileName) == ".dae")
GetRealNodeNames(FileName); GetRealNodeNames(FileName);
@ -220,16 +219,28 @@ namespace Toolbox.Library
if (scene.RootNode != null) if (scene.RootNode != null)
{ {
var idenity = Matrix4x4.Identity; var rootTransform = scene.RootNode.Transform;
Matrix4 transformMat = AssimpHelper.TKMatrix(rootTransform);
var scale = transformMat.ExtractScale();
var rotation = transformMat.ExtractRotation();
var position = transformMat.ExtractTranslation();
STConsole.WriteLine($"-".Repeat(30));
STConsole.WriteLine($"rootTransform {transformMat}");
STConsole.WriteLine($"scale {scale}");
STConsole.WriteLine($"rotation {rotation}");
STConsole.WriteLine($"position {position}");
STConsole.WriteLine($"-".Repeat(30));
var SklRoot = GetSklRoot(scene.RootNode, BoneNames); var SklRoot = GetSklRoot(scene.RootNode, BoneNames);
if (SklRoot != null) if (SklRoot != null)
{ {
BuildSkeletonNodes(SklRoot, BoneNames, skeleton, ref idenity); BuildSkeletonNodes(SklRoot, BoneNames, skeleton, ref rootTransform);
} }
else else
{ {
BuildSkeletonNodes(scene.RootNode, BoneNames, skeleton, ref idenity); BuildSkeletonNodes(scene.RootNode, BoneNames, skeleton, ref rootTransform);
} }
skeleton.update(); skeleton.update();
@ -513,12 +524,12 @@ namespace Toolbox.Library
if (IsBone) if (IsBone)
{ {
var idenity = Matrix4x4.Identity; var idenity = Matrix4x4.Identity;
CreateByNode(node, skeleton, ParentArmatureName, SmoothIndex, RigidIndex, true, ref idenity); CreateByNode(node, skeleton, ParentArmatureName, SmoothIndex, RigidIndex, true, ref rootTransform);
} }
else if (IsRootSkeleton && node.HasChildren) else if (IsRootSkeleton && node.HasChildren)
{ {
var idenity = Matrix4x4.Identity; var idenity = Matrix4x4.Identity;
CreateByNode(node.Children[0], skeleton, ParentArmatureName, SmoothIndex, RigidIndex, true, ref idenity); CreateByNode(node.Children[0], skeleton, ParentArmatureName, SmoothIndex, RigidIndex, true, ref world);
} }
else else
{ {
@ -535,7 +546,7 @@ namespace Toolbox.Library
short SmoothIndex, short RigidIndex, bool IsRoot, ref Assimp.Matrix4x4 rootTransform) short SmoothIndex, short RigidIndex, bool IsRoot, ref Assimp.Matrix4x4 rootTransform)
{ {
Matrix4x4 trafo = node.Transform; Matrix4x4 trafo = node.Transform;
Matrix4x4 world = trafo; Matrix4x4 world = trafo * rootTransform;
var transformMat = AssimpHelper.TKMatrix(world); var transformMat = AssimpHelper.TKMatrix(world);
int matchedBoneIndex = skeleton.bones.FindIndex(item => item.Name == node.Name); int matchedBoneIndex = skeleton.bones.FindIndex(item => item.Name == node.Name);
@ -557,13 +568,6 @@ namespace Toolbox.Library
bone.SmoothMatrixIndex = (short)skeleton.bones.IndexOf(bone); bone.SmoothMatrixIndex = (short)skeleton.bones.IndexOf(bone);
bone.RigidMatrixIndex = -1; //Todo calculate these bone.RigidMatrixIndex = -1; //Todo calculate these
STConsole.WriteLine($"-".Repeat(30));
STConsole.WriteLine($"Processing Bone {bone.Text}");
STConsole.WriteLine($"SmoothMatrixIndex {bone.SmoothMatrixIndex}");
STConsole.WriteLine($"RigidMatrixIndex {bone.RigidMatrixIndex}");
STConsole.WriteLine($"Transform Matrix {transformMat}");
STConsole.WriteLine($"-".Repeat(30));
if (IsRoot) if (IsRoot)
{ {
bone.parentIndex = -1; bone.parentIndex = -1;
@ -584,19 +588,25 @@ namespace Toolbox.Library
var rotation = transformMat.ExtractRotation(); var rotation = transformMat.ExtractRotation();
var position = transformMat.ExtractTranslation(); var position = transformMat.ExtractTranslation();
STConsole.WriteLine($"-".Repeat(30));
STConsole.WriteLine($"Processing Bone {bone.Text}");
STConsole.WriteLine($"scale {scale}");
STConsole.WriteLine($"rotation {rotation}");
STConsole.WriteLine($"position {position}");
STConsole.WriteLine($"-".Repeat(30));
var rotEular = STMath.ToEulerAngles(rotation); var rotEular = STMath.ToEulerAngles(rotation);
bone.position = new float[] { position.X, position.Y, position.Z }; bone.Transform = transformMat;
bone.scale = new float[] { scale.X, scale.Y, scale.Z };
bone.rotation = new float[] { rotEular.X, rotEular.Y, rotEular.Z, 1 };
} }
else else
{ {
STConsole.WriteLine($"Duplicate node name found for bone {node.Name}!", Color.Red); STConsole.WriteLine($"Duplicate node name found for bone {node.Name}!", Color.Red);
} }
var identity = Matrix4x4.Identity;
foreach (Node child in node.Children) foreach (Node child in node.Children)
CreateByNode(child, skeleton, ParentArmatureName, SmoothIndex, RigidIndex, false, ref rootTransform); CreateByNode(child, skeleton, ParentArmatureName, SmoothIndex, RigidIndex, false, ref identity);
} }
public STGenericObject CreateGenericObject(Node parentNode,Mesh msh, int Index, Matrix4 transform) public STGenericObject CreateGenericObject(Node parentNode,Mesh msh, int Index, Matrix4 transform)
{ {
@ -623,6 +633,8 @@ namespace Toolbox.Library
obj.HasTans = msh.HasTangentBasis; obj.HasTans = msh.HasTangentBasis;
obj.HasBitans = msh.HasTangentBasis; obj.HasBitans = msh.HasTangentBasis;
obj.HasVertColors = msh.HasVertexColors(0); obj.HasVertColors = msh.HasVertexColors(0);
obj.HasVertColors2 = msh.HasVertexColors(1);
obj.ObjectName = msh.Name; obj.ObjectName = msh.Name;
if (parentNode != null && msh.Name == string.Empty) if (parentNode != null && msh.Name == string.Empty)
obj.ObjectName = parentNode.Name; obj.ObjectName = parentNode.Name;
@ -640,6 +652,18 @@ namespace Toolbox.Library
obj.vertices = GetVertices(msh, transform, obj); obj.vertices = GetVertices(msh, transform, obj);
obj.VertexBufferIndex = Index; obj.VertexBufferIndex = Index;
//Correct the vertex colors because assimp is broken.
if (Geomerties.Count > Index)
{
Console.WriteLine($"v count {obj.vertices.Count}");
Console.WriteLine($"color count {Geomerties[Index].ColorList.Count}");
for (int v = 0; v < Geomerties[Index].ColorList.Count; v++) {
if (v < obj.vertices.Count)
obj.vertices[v].col = Geomerties[Index].ColorList[v];
}
}
return obj; return obj;
} }
@ -651,8 +675,7 @@ namespace Toolbox.Library
{ {
foreach (Face f in msh.Faces) foreach (Face f in msh.Faces)
{ {
if (f.HasIndices) if (f.HasIndices) {
{
foreach (int indx in f.Indices) foreach (int indx in f.Indices)
faces.Add(indx); faces.Add(indx);
} }
@ -710,6 +733,8 @@ namespace Toolbox.Library
{ {
Vertex vert = new Vertex(); Vertex vert = new Vertex();
Console.WriteLine($"{msh.Name} position {msh.Vertices[v]}");
if (msh.HasVertices) if (msh.HasVertices)
vert.pos = Vector3.TransformPosition(AssimpHelper.FromVector(msh.Vertices[v]), transform); vert.pos = Vector3.TransformPosition(AssimpHelper.FromVector(msh.Vertices[v]), transform);
if (msh.HasNormals) if (msh.HasNormals)
@ -722,10 +747,11 @@ namespace Toolbox.Library
vert.uv2 = new Vector2(msh.TextureCoordinateChannels[2][v].X, msh.TextureCoordinateChannels[2][v].Y); vert.uv2 = new Vector2(msh.TextureCoordinateChannels[2][v].X, msh.TextureCoordinateChannels[2][v].Y);
if (msh.HasTangentBasis) if (msh.HasTangentBasis)
vert.tan = new Vector4(msh.Tangents[v].X, msh.Tangents[v].Y, msh.Tangents[v].Z, 1); vert.tan = new Vector4(msh.Tangents[v].X, msh.Tangents[v].Y, msh.Tangents[v].Z, 1);
if (msh.HasVertexColors(0)) //Todo Assimp always reads vertex colors wrong!
{ // if (msh.HasVertexColors(0))
vert.col = new Vector4(msh.VertexColorChannels[0][v].R, msh.VertexColorChannels[0][v].G, msh.VertexColorChannels[0][v].B, msh.VertexColorChannels[0][v].A); // vert.col = new Vector4(msh.VertexColorChannels[0][v].R, msh.VertexColorChannels[0][v].G, msh.VertexColorChannels[0][v].B, msh.VertexColorChannels[0][v].A);
} // if (msh.HasVertexColors(1))
// vert.col2 = new Vector4(msh.VertexColorChannels[1][v].R, msh.VertexColorChannels[1][v].G, msh.VertexColorChannels[1][v].B, msh.VertexColorChannels[1][v].A);
if (msh.HasTangentBasis) if (msh.HasTangentBasis)
vert.bitan = new Vector4(msh.BiTangents[v].X, msh.BiTangents[v].Y, msh.BiTangents[v].Z, 1); vert.bitan = new Vector4(msh.BiTangents[v].X, msh.BiTangents[v].Y, msh.BiTangents[v].Z, 1);
vertices.Add(vert); vertices.Add(vert);

View File

@ -11,15 +11,8 @@ namespace Toolbox.Library
{ {
public static class AssimpHelper public static class AssimpHelper
{ {
public static Matrix4x4 GetBoneMatrix(STBone bone) public static Matrix4x4 GetBoneMatrix(STBone bone) {
{ return AssimpFromTKMatrix(bone.Transform);
var pos = Matrix4x4.FromTranslation(new Vector3D(bone.position[0], bone.position[1], bone.position[2]));
var rotx = Matrix4x4.FromRotationX(bone.rotation[0]);
var roty = Matrix4x4.FromRotationY(bone.rotation[1]);
var rotz = Matrix4x4.FromRotationZ(bone.rotation[2]);
var sca = Matrix4x4.FromScaling(new Vector3D(bone.scale[0], bone.scale[1], bone.scale[2]));
return sca * (rotx * roty * rotz) * pos;
} }
public static string GetSaveFilter() public static string GetSaveFilter()
@ -35,11 +28,6 @@ namespace Toolbox.Library
"All files(*.*)|*.*"; "All files(*.*)|*.*";
} }
public static Syroot.Maths.Matrix3x4 CalculateInverseMatrix(STBone bone)
{
return FromAssimpMatrix(AssimpCalculateInverseMatrix(bone));
}
public static Syroot.Maths.Matrix3x4 FromAssimpMatrix(Assimp.Matrix4x4 mat) public static Syroot.Maths.Matrix3x4 FromAssimpMatrix(Assimp.Matrix4x4 mat)
{ {
@ -64,30 +52,6 @@ namespace Toolbox.Library
return mat4; return mat4;
} }
public static Assimp.Matrix4x4 AssimpCalculateInverseMatrix(STBone bone)
{
Assimp.Matrix4x4 transf;
//Get parent transform for a smooth matrix
if (bone.Parent != null && bone.Parent is STBone)
transf = AssimpCalculateInverseMatrix((STBone)bone.Parent);
else
transf = Assimp.Matrix4x4.Identity;
//Now calculate the matrix with TK matrices
var trans = Assimp.Matrix4x4.FromTranslation(new Vector3D(bone.position[0], bone.position[1], bone.position[2]));
var scale = Assimp.Matrix4x4.FromScaling(new Vector3D(bone.scale[0], bone.scale[1], bone.scale[2]));
var rotX = Assimp.Matrix4x4.FromRotationX(bone.rotation[0]);
var rotY = Assimp.Matrix4x4.FromRotationY(bone.rotation[1]);
var rotZ = Assimp.Matrix4x4.FromRotationZ(bone.rotation[2]);
var result = scale * (rotX * rotY * rotZ) * trans;
result.Inverse();
return transf;
}
public static Vector3 FromVector(Vector3D vec) public static Vector3 FromVector(Vector3D vec)
{ {
Vector3 v; Vector3 v;

View File

@ -75,12 +75,20 @@ namespace Toolbox.Library
bone.Text = seBone.BoneName; bone.Text = seBone.BoneName;
bone.parentIndex = seBone.BoneParent; bone.parentIndex = seBone.BoneParent;
bone.RotationType = STBone.BoneRotationType.Euler; bone.RotationType = STBone.BoneRotationType.Euler;
Vector3 rotEular = ToEular(seBone.LocalRotation);
bone.position = new float[] { (float)seBone.LocalPosition.X, (float)seBone.LocalPosition.Y, (float)seBone.LocalPosition.Z }; bone.Position = new Vector3(
bone.scale = new float[] { (float)seBone.Scale.X, (float)seBone.Scale.Y, (float)seBone.Scale.Z }; (float)seBone.LocalPosition.X,
bone.rotation = new float[] { rotEular.X, rotEular.Y, rotEular.Z, 0 }; (float)seBone.LocalPosition.Y,
(float)seBone.LocalPosition.Z);
bone.Scale = new Vector3(
(float)seBone.Scale.X,
(float)seBone.Scale.Y,
(float)seBone.Scale.Z);
bone.Rotation = new Quaternion(
(float)seBone.LocalRotation.X,
(float)seBone.LocalRotation.Y,
(float)seBone.LocalRotation.Z,
(float)seBone.LocalRotation.W);
return bone; return bone;
} }
@ -208,31 +216,5 @@ namespace Toolbox.Library
(float)(value.B / 255), (float)(value.B / 255),
(float)(value.A / 255)); (float)(value.A / 255));
} }
private static Vector3 ToEular(SELib.Utilities.Quaternion selibQuat)
{
OpenTK.Quaternion q = new Quaternion((float)selibQuat.X, (float)selibQuat.Y, (float)selibQuat.Z, (float)selibQuat.W);
Matrix4 mat = Matrix4.CreateFromQuaternion(q);
float x, y, z;
y = (float)Math.Asin(Clamp(mat.M13, -1, 1));
if (Math.Abs(mat.M13) < 0.99999)
{
x = (float)Math.Atan2(-mat.M23, mat.M33);
z = (float)Math.Atan2(-mat.M12, mat.M11);
}
else
{
x = (float)Math.Atan2(mat.M32, mat.M22);
z = 0;
}
return new Vector3(x, y, z) * -1;
}
private static float Clamp(float v, float min, float max)
{
if (v < min) return min;
if (v > max) return max;
return v;
}
} }
} }

View File

@ -29,28 +29,91 @@ namespace Toolbox.Library
public short RigidMatrixIndex; public short RigidMatrixIndex;
public short SmoothMatrixIndex; public short SmoothMatrixIndex;
public float[] position = new float[] { 0, 0, 0 }; private Matrix4 transform;
public float[] rotation = new float[] { 0, 0, 0 }; private Quaternion rotation;
public float[] scale = new float[] { 1, 1, 1 }; private Vector3 eulerRotation;
/// <summary>
/// Gets or sets the transformation of the bone.
/// Setting this will adjust the
/// <see cref="Scale"/>,
/// <see cref="Rotation"/>, and
/// <see cref="Position"/> properties.
/// </summary>
public Matrix4 Transform
{
set
{
// Scale = value.ExtractScale();
// Rotation = value.ExtractRotation();
// Position = value.ExtractTranslation();
transform = value;
}
get
{
return transform;
}
}
/// <summary>
/// Gets or sets the position of the bone in world space.
/// </summary>
public Vector3 Position { get; set; }
/// <summary>
/// Gets or sets the scale of the bone in world space.
/// </summary>
public Vector3 Scale { get; set; }
/// <summary>
/// Gets or sets the rotation of the bone in world space.
/// </summary>
public Quaternion Rotation
{
get { return rotation; }
set
{
if (RotationType == BoneRotationType.Euler)
{
eulerRotation = new Vector3(value.X, value.Y, value.Z);
rotation = STMath.FromEulerAngles(eulerRotation);
}
else
{
eulerRotation = STMath.ToEulerAngles(Rotation);
rotation = value;
}
}
}
/// <summary>
/// Gets or sets the <see cref="Rotation"/> using euler method.
/// </summary>
public Vector3 EulerRotation
{
get { return eulerRotation; }
set {
eulerRotation = value;
rotation = STMath.FromEulerAngles(value);
}
}
public Vector3 pos = Vector3.Zero, sca = new Vector3(1f, 1f, 1f); public Vector3 pos = Vector3.Zero, sca = new Vector3(1f, 1f, 1f);
public Quaternion rot = Quaternion.FromMatrix(Matrix3.Zero); public Quaternion rot = Quaternion.FromMatrix(Matrix3.Zero);
public Matrix4 Transform, invert; public Matrix4 invert;
public Matrix4 GetTransform() public Matrix4 GetTransform()
{ {
Vector3 mPos = new Vector3(position[0], position[1],position[2]); return Matrix4.CreateScale(Scale) *
Matrix4.CreateFromQuaternion(Rotation) *
Matrix4.CreateTranslation(Position);
}
Quaternion mRot; public void FromTransform(Matrix4 transform)
if (RotationType == STBone.BoneRotationType.Quaternion) {
mRot = (STSkeleton.FromQuaternionAngles(rotation[2], rotation[1],rotation[0], rotation[3])); Scale = transform.ExtractScale();
else Position = transform.ExtractTranslation();
mRot = (STSkeleton.FromEulerAngles(rotation[2],rotation[1],rotation[0])); Rotation = transform.ExtractRotation();
Vector3 mSca = new Vector3(scale[0], scale[1],scale[2]);
return Matrix4.CreateScale(mSca) * Matrix4.CreateFromQuaternion(mRot) * Matrix4.CreateTranslation(mPos);
} }
//Used for shifting models with the bones in the shader //Used for shifting models with the bones in the shader
@ -71,38 +134,6 @@ namespace Toolbox.Library
return sca; return sca;
} }
public void FromTransform(Matrix4 Transform)
{
var pos = Transform.ExtractTranslation();
var quat = Transform.ExtractRotation();
var scale = Transform.ExtractScale();
position[0] = pos.X;
position[1] = pos.X;
position[2] = pos.Z;
var eul = Toolbox.Library.Animations.ANIM.quattoeul(quat);
rotation = new float[] { eul.X, eul.Y, eul.Z, 1 };
scale[0] = scale.X;
scale[1] = scale.X;
scale[2] = scale.Z;
}
private void ApplyTransforms()
{
position = new float[] { pos.X, pos .Y, pos .Z};
if (RotationType == BoneRotationType.Quaternion)
rotation = new float[] { rot.X, rot.Y, rot.Z, rot.W };
else
{
var eul = Toolbox.Library.Animations.ANIM.quattoeul(rot);
rotation = new float[] { eul.X, eul.Y, eul.Z, 1 };
}
scale = new float[] { sca.X, sca.Y, sca.Z };
}
public int GetIndex() public int GetIndex()
{ {
if (skeletonParent != null) if (skeletonParent != null)
@ -111,34 +142,6 @@ namespace Toolbox.Library
return -1; return -1;
} }
public void ConvertToQuaternion()
{
if (RotationType == BoneRotationType.Quaternion)
return;
RotationType = STBone.BoneRotationType.Quaternion;
ApplyTransforms();
//Update matrices
skeletonParent.reset();
skeletonParent.update();
}
public void ConvertToEular()
{
if (RotationType == BoneRotationType.Euler)
return;
RotationType = STBone.BoneRotationType.Euler;
ApplyTransforms();
//Update matrices
skeletonParent.reset();
skeletonParent.update();
}
public override void OnClick(TreeView treeView) public override void OnClick(TreeView treeView)
{ {
@ -183,9 +186,9 @@ namespace Toolbox.Library
public STBone(STSkeleton skl) public STBone(STSkeleton skl)
{ {
skeletonParent = skl; skeletonParent = skl;
ImageKey = "bone"; ImageKey = "bone";
SelectedImageKey = "bone"; SelectedImageKey = "bone";
Checked = true; Checked = true;
} }
@ -193,6 +196,7 @@ namespace Toolbox.Library
{ {
ImageKey = "bone"; ImageKey = "bone";
SelectedImageKey = "bone"; SelectedImageKey = "bone";
Checked = true;
} }
public void RenderLegacy() public void RenderLegacy()

View File

@ -287,6 +287,10 @@ namespace Toolbox.Library
return bone; return bone;
} }
public Matrix4 GetBoneTransform(int index) {
return GetBoneTransform(bones[index]);
}
public Matrix4 GetBoneTransform(STBone Bone) public Matrix4 GetBoneTransform(STBone Bone)
{ {
if (Bone == null) if (Bone == null)
@ -314,17 +318,19 @@ namespace Toolbox.Library
{ {
for (int i = 0; i < bones.Count; i++) for (int i = 0; i < bones.Count; i++)
{ {
bones[i].pos = new Vector3(bones[i].position[0], bones[i].position[1], bones[i].position[2]); bones[i].pos = new Vector3(
bones[i].Position.X,
if (bones[i].RotationType == STBone.BoneRotationType.Quaternion) bones[i].Position.Y,
{ bones[i].Position.Z);
bones[i].rot = (FromQuaternionAngles(bones[i].rotation[2], bones[i].rotation[1], bones[i].rotation[0], bones[i].rotation[3])); bones[i].rot = new Quaternion(
} bones[i].Rotation.X,
else bones[i].Rotation.Y,
{ bones[i].Rotation.Z,
bones[i].rot = (FromEulerAngles(bones[i].rotation[2], bones[i].rotation[1], bones[i].rotation[0])); bones[i].Rotation.W);
} bones[i].sca = new Vector3(
bones[i].sca = new Vector3(bones[i].scale[0], bones[i].scale[1], bones[i].scale[2]); bones[i].Scale.X,
bones[i].Scale.Y,
bones[i].Scale.Z);
} }
update(true); update(true);
for (int i = 0; i < bones.Count; i++) for (int i = 0; i < bones.Count; i++)

View File

@ -57,6 +57,7 @@ namespace Toolbox.Library.IO
{ {
if (offset < 0) throw new ArgumentOutOfRangeException(nameof(offset)); if (offset < 0) throw new ArgumentOutOfRangeException(nameof(offset));
Console.WriteLine("bytes to struct isBigEndian " + isBigEndian);
AdjustBigEndianByteOrder(typeof(T), buffer, isBigEndian); AdjustBigEndianByteOrder(typeof(T), buffer, isBigEndian);
fixed (byte* pBuffer = buffer) fixed (byte* pBuffer = buffer)
@ -82,6 +83,8 @@ namespace Toolbox.Library.IO
if (!isBigEndian) if (!isBigEndian)
return; return;
Console.WriteLine("type " + type + " " + type.IsPrimitive);
if (type.IsPrimitive) if (type.IsPrimitive)
{ {
if (type == typeof(short) || type == typeof(ushort) || if (type == typeof(short) || type == typeof(ushort) ||
@ -93,6 +96,8 @@ namespace Toolbox.Library.IO
} }
} }
Console.WriteLine("GetFields " + type.GetFields().Length);
foreach (var field in type.GetFields()) foreach (var field in type.GetFields())
{ {
var fieldType = field.FieldType; var fieldType = field.FieldType;

View File

@ -12,38 +12,38 @@ namespace Toolbox.Library.IO
public static float Deg2Rad = (float)(System.Math.PI * 2) / 360; public static float Deg2Rad = (float)(System.Math.PI * 2) / 360;
public static float Rad2Deg = (float)(360 / (System.Math.PI * 2)); public static float Rad2Deg = (float)(360 / (System.Math.PI * 2));
public static OpenTK.Vector3 QuaternionToEuler(OpenTK.Quaternion q1) public static OpenTK.Vector3 QuaternionToEuler(OpenTK.Quaternion q1)
{ {
float sqw = q1.W * q1.W; float sqw = q1.W * q1.W;
float sqx = q1.X * q1.X; float sqx = q1.X * q1.X;
float sqy = q1.Y * q1.Y; float sqy = q1.Y * q1.Y;
float sqz = q1.Z * q1.Z; float sqz = q1.Z * q1.Z;
float unit = sqx + sqy + sqz + sqw; // if normalised is one, otherwise is correction factor float unit = sqx + sqy + sqz + sqw; // if normalised is one, otherwise is correction factor
float test = q1.X * q1.W - q1.Y * q1.Z; float test = q1.X * q1.W - q1.Y * q1.Z;
OpenTK.Vector3 v; OpenTK.Vector3 v;
if (test > 0.4995f * unit) if (test > 0.4995f * unit)
{ // singularity at north pole { // singularity at north pole
v.Y = 2f * (float)System.Math.Atan2(q1.X, q1.Y); v.Y = 2f * (float)System.Math.Atan2(q1.X, q1.Y);
v.X = (float)System.Math.PI / 2; v.X = (float)System.Math.PI / 2;
v.Z = 0; v.Z = 0;
return NormalizeAngles(v * Rad2Deg);
}
if (test < -0.4995f * unit)
{ // singularity at south pole
v.Y = -2f * (float)System.Math.Atan2(q1.Y, q1.X);
v.X = (float)-System.Math.PI / 2;
v.Z = 0;
return NormalizeAngles(v * Rad2Deg);
}
Quaternion q = new Quaternion(q1.W, q1.Z, q1.X, q1.Y);
v.Y = (float)Math.Atan2(2f * q.X * q.W + 2f * q.Y * q.Z, 1 - 2f * (q.Z * q.Z + q.W * q.W)); // Yaw
v.X = (float)Math.Asin(2f * (q.X * q.Z - q.W * q.Y)); // Pitch
v.Z = (float)Math.Atan2(2f * q.X * q.Y + 2f * q.Z * q.W, 1 - 2f * (q.Y * q.Y + q.Z * q.Z)); // Roll
return NormalizeAngles(v * Rad2Deg); return NormalizeAngles(v * Rad2Deg);
} }
if (test < -0.4995f * unit)
{ // singularity at south pole
v.Y = -2f * (float)System.Math.Atan2(q1.Y, q1.X);
v.X = (float)-System.Math.PI / 2;
v.Z = 0;
return NormalizeAngles(v * Rad2Deg);
}
Quaternion q = new Quaternion(q1.W, q1.Z, q1.X, q1.Y);
v.Y = (float)Math.Atan2(2f * q.X * q.W + 2f * q.Y * q.Z, 1 - 2f * (q.Z * q.Z + q.W * q.W)); // Yaw
v.X = (float)Math.Asin(2f * (q.X * q.Z - q.W * q.Y)); // Pitch
v.Z = (float)Math.Atan2(2f * q.X * q.Y + 2f * q.Z * q.W, 1 - 2f * (q.Y * q.Y + q.Z * q.Z)); // Roll
return NormalizeAngles(v * Rad2Deg);
}
static OpenTK.Vector3 NormalizeAngles(OpenTK.Vector3 angles) static OpenTK.Vector3 NormalizeAngles(OpenTK.Vector3 angles)
{ {
@ -116,18 +116,19 @@ namespace Toolbox.Library.IO
public static Matrix4x4 CalculateTransformMatrix(STBone bone) public static Matrix4x4 CalculateTransformMatrix(STBone bone)
{ {
var trans = Matrix4x4.CreateTranslation(new Vector3(bone.position[0], bone.position[1], bone.position[2])); var trans = Matrix4x4.CreateTranslation(new Vector3(bone.Position.X, bone.Position.Y, bone.Position.Z));
var scale = Matrix4x4.CreateScale(new Vector3(bone.scale[0], bone.scale[1], bone.scale[2])); var scale = Matrix4x4.CreateScale(new Vector3(bone.Scale.X, bone.Scale.Y, bone.Scale.Z));
Matrix4x4 quat = Matrix4x4.Identity; Matrix4x4 quat = Matrix4x4.Identity;
if (bone.RotationType == STBone.BoneRotationType.Euler) if (bone.RotationType == STBone.BoneRotationType.Euler)
quat = Matrix4x4.CreateFromQuaternion(QuatFromEular(bone.rotation[0], bone.rotation[1], bone.rotation[2])); quat = Matrix4x4.CreateFromQuaternion(QuatFromEular(bone.EulerRotation.X, bone.EulerRotation.Y, bone.EulerRotation.Z));
else else
quat = Matrix4x4.CreateFromQuaternion(QuatFromQuat(bone.rotation[0], bone.rotation[1], bone.rotation[2], bone.rotation[3])); quat = Matrix4x4.CreateFromQuaternion(QuatFromQuat(bone.Rotation.X, bone.Rotation.Y, bone.Rotation.Z, bone.Rotation.W));
return Matrix4x4.Multiply(quat, trans); return Matrix4x4.Multiply(quat, trans);
} }
public static Matrices CalculateInverseMatrix(STBone bone) public static Matrices CalculateInverseMatrix(STBone bone)
{ {
var matrices = new Matrices(); var matrices = new Matrices();
@ -138,18 +139,7 @@ namespace Toolbox.Library.IO
else else
matrices.transform = Matrix4x4.Identity; matrices.transform = Matrix4x4.Identity;
//Now calculate the matrix with TK matrices matrices.transform = Matrix4x4.Multiply(CalculateTransformMatrix(bone), matrices.transform);
var trans = Matrix4x4.CreateTranslation(new Vector3(bone.position[0], bone.position[1], bone.position[2]));
var scale = Matrix4x4.CreateScale(new Vector3(bone.scale[0], bone.scale[1], bone.scale[2]));
Matrix4x4 quat = Matrix4x4.Identity;
if (bone.RotationType == STBone.BoneRotationType.Euler)
quat = Matrix4x4.CreateFromQuaternion(QuatFromEular(bone.rotation[0], bone.rotation[1], bone.rotation[2]));
else
quat = Matrix4x4.CreateFromQuaternion(QuatFromQuat(bone.rotation[0], bone.rotation[1], bone.rotation[2], bone.rotation[3]));
matrices.transform = Matrix4x4.Multiply(Matrix4x4.Multiply(quat, trans), matrices.transform);
Matrix4x4 Inverse; Matrix4x4 Inverse;
Matrix4x4.Invert(matrices.transform, out Inverse); Matrix4x4.Invert(matrices.transform, out Inverse);
@ -242,19 +232,46 @@ namespace Toolbox.Library.IO
M32 = mat.M23, M32 = mat.M23,
M33 = mat.M33, M33 = mat.M33,
M34 = mat.M43, M34 = mat.M43,
};
}
/* M11 = mat.M11, public static OpenTK.Matrix4 ToTKMatrix4x4(this Matrix4x4 mat)
M12 = mat.M12, {
M13 = mat.M13, if (mat.M11 == -0) mat.M11 = 0;
M14 = mat.M14, if (mat.M12 == -0) mat.M12 = 0;
M21 = mat.M21, if (mat.M13 == -0) mat.M13 = 0;
M22 = mat.M22, if (mat.M14 == -0) mat.M14 = 0;
M23 = mat.M23, if (mat.M21 == -0) mat.M21 = 0;
M24 = mat.M24, if (mat.M22 == -0) mat.M22 = 0;
M31 = mat.M31, if (mat.M23 == -0) mat.M23 = 0;
M32 = mat.M32, if (mat.M24 == -0) mat.M24 = 0;
M33 = mat.M33, if (mat.M31 == -0) mat.M31 = 0;
M34 = mat.M34,*/ if (mat.M32 == -0) mat.M32 = 0;
if (mat.M33 == -0) mat.M33 = 0;
if (mat.M34 == -0) mat.M34 = 0;
if (mat.M41 == -0) mat.M41 = 0;
if (mat.M42 == -0) mat.M42 = 0;
if (mat.M43 == -0) mat.M43 = 0;
if (mat.M44 == -0) mat.M44 = 0;
return new OpenTK.Matrix4()
{
M11 = mat.M11,
M12 = mat.M21,
M13 = mat.M31,
M14 = mat.M41,
M21 = mat.M12,
M22 = mat.M22,
M23 = mat.M32,
M24 = mat.M42,
M31 = mat.M13,
M32 = mat.M23,
M33 = mat.M33,
M34 = mat.M44,
M41 = mat.M14,
M42 = mat.M24,
M43 = mat.M34,
M44 = mat.M44,
}; };
} }
} }

View File

@ -206,7 +206,7 @@ namespace Toolbox.Library.Rendering
} }
private static void SetBoneUniforms(GLControl control, ShaderProgram shader, STSkeleton Skeleton, STGenericObject mesh) public virtual void SetBoneUniforms(GLControl control, ShaderProgram shader, STSkeleton Skeleton, STGenericObject mesh)
{ {
int i = 0; int i = 0;
foreach (var bone in Skeleton.bones) foreach (var bone in Skeleton.bones)
@ -214,20 +214,6 @@ namespace Toolbox.Library.Rendering
Matrix4 transform = bone.invert * bone.Transform; Matrix4 transform = bone.invert * bone.Transform;
GL.UniformMatrix4(GL.GetUniformLocation(shader.programs[control], String.Format("bones[{0}]", i++)), false, ref transform); GL.UniformMatrix4(GL.GetUniformLocation(shader.programs[control], String.Format("bones[{0}]", i++)), false, ref transform);
} }
/* foreach (var FaceGroup in fshp.Shape.FaceGroups)
{
if (FaceGroup.BoneIndexList == null)
continue;
for (int i = 0; i < FaceGroup.BoneIndexList.Length; i++)
{
GL.Uniform1(GL.GetUniformLocation(shader.programs[control], String.Format("boneIds[{0}]", i)), FaceGroup.BoneIndexList[i]);
Matrix4 transform = fmdl.Skeleton.Renderable.bones[(int)FaceGroup.BoneIndexList[i]].invert * fmdl.Skeleton.Renderable.bones[(int)FaceGroup.BoneIndexList[i]].Transform;
GL.UniformMatrix4(GL.GetUniformLocation(shader.programs[control], String.Format("bones[{0}]", i)), false, ref transform);
}
}*/
} }
private void SetUniformBlocks(STGenericMaterial mat, ShaderProgram shader, STGenericObject m) private void SetUniformBlocks(STGenericMaterial mat, ShaderProgram shader, STGenericObject m)
@ -423,6 +409,9 @@ namespace Toolbox.Library.Rendering
if (group.faces.Count <= 3) if (group.faces.Count <= 3)
return; return;
if (group.Material != null)
Material = group.Material;
SetRenderData(Material, shader, m); SetRenderData(Material, shader, m);
SetUniforms(Material, shader, m); SetUniforms(Material, shader, m);
SetUniformBlocks(Material, shader, m); SetUniformBlocks(Material, shader, m);
@ -430,7 +419,7 @@ namespace Toolbox.Library.Rendering
SetVertexAttributes(m, shader); SetVertexAttributes(m, shader);
SetTextureUniforms(Material, m, shader); SetTextureUniforms(Material, m, shader);
if (m.IsSelected || m.GetMaterial().IsSelected) if (m.IsSelected || Material.IsSelected)
{ {
DrawModelSelection(group, shader); DrawModelSelection(group, shader);
} }

View File

@ -347,11 +347,6 @@ namespace Toolbox
editor.Show(); editor.Show();
((ObjectEditor)editor).SelectFirstNode(); ((ObjectEditor)editor).SelectFirstNode();
if (file is TreeNodeFile)
{
((TreeNodeFile)file).OnAfterAdded();
}
} }
else else
{ {
@ -360,8 +355,10 @@ namespace Toolbox
else else
AddObjectEditorFile(((TreeNode)file), (ObjectEditor)editor, false); AddObjectEditorFile(((TreeNode)file), (ObjectEditor)editor, false);
} }
SetFormatSettings(GetActiveIFileFormat()); SetFormatSettings(GetActiveIFileFormat());
if (file is TreeNodeFile)
((TreeNodeFile)file).OnAfterAdded();
} }
private void AddObjectEditorFile(TreeNode file, ObjectEditor editor, bool ClearFiles) private void AddObjectEditorFile(TreeNode file, ObjectEditor editor, bool ClearFiles)